{"id":13414122,"url":"https://github.com/nikogura/dbt","last_synced_at":"2026-02-14T18:07:53.274Z","repository":{"id":55504652,"uuid":"112669754","full_name":"nikogura/dbt","owner":"nikogura","description":"A delivery system for running self-updating, signed tools.","archived":false,"fork":false,"pushed_at":"2026-02-05T22:16:56.000Z","size":790,"stargazers_count":67,"open_issues_count":6,"forks_count":9,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-02-06T03:06:26.475Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nikogura.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2017-11-30T22:53:17.000Z","updated_at":"2026-02-05T22:08:08.000Z","dependencies_parsed_at":"2024-06-19T00:02:09.780Z","dependency_job_id":"7f32ae58-8d7a-43a3-8015-182046915455","html_url":"https://github.com/nikogura/dbt","commit_stats":null,"previous_names":[],"tags_count":50,"template":false,"template_full_name":null,"purl":"pkg:github/nikogura/dbt","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikogura%2Fdbt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikogura%2Fdbt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikogura%2Fdbt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikogura%2Fdbt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nikogura","download_url":"https://codeload.github.com/nikogura/dbt/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikogura%2Fdbt/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29452178,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-14T15:52:44.973Z","status":"ssl_error","status_checked_at":"2026-02-14T15:52:11.208Z","response_time":53,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-30T20:01:58.274Z","updated_at":"2026-02-14T18:07:53.268Z","avatar_url":"https://github.com/nikogura.png","language":"Go","funding_links":[],"categories":["Utilities","公用事业公司","Utility","工具库`可以提升效率的通用代码库和工具`","工具库"],"sub_categories":["Utility/Miscellaneous","HTTP Clients","实用程序/Miscellaneous","Fail injection","查询语"],"readme":"# DBT (Dynamic Binary Toolkit)\n\n**A secure, self-updating binary distribution system for organizations.**\n\nDBT automatically downloads, verifies, and runs signed executables from a trusted repository, ensuring your team always uses the latest, secure versions of your tools without manual intervention.\n\n[![Current Release](https://img.shields.io/github/release/nikogura/dbt.svg)](https://img.shields.io/github/release/nikogura/dbt.svg)\n[![CI](https://github.com/nikogura/dbt/actions/workflows/ci.yml/badge.svg)](https://github.com/nikogura/dbt/actions/workflows/ci.yml)\n[![Go Report Card](https://goreportcard.com/badge/github.com/nikogura/dbt)](https://goreportcard.com/report/github.com/nikogura/dbt)\n[![Go Doc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](http://godoc.org/github.com/nikogura/dbt/pkg/dbt)\n[![Coverage Status](https://codecov.io/gh/nikogura/dbt/branch/master/graph/badge.svg)](https://codecov.io/gh/nikogura/dbt)\n[![Mentioned in Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go)\n\n## How It Works\n\nDBT is a secure downloader and verifier for executable files.  When a user runs a tool through DBT:\n\n1. **Self-update**: DBT checks if it needs to update itself\n2. **Download**: Fetches the requested tool from your repository\n3. **Verify**: Checks the SHA256 checksum and GPG signature against your truststore\n4. **Execute**: Runs the verified tool, replacing itself in the process table\n\nIf any verification step fails, DBT stops immediately and reports the error.  No unverified code ever runs.\n\n```mermaid\nsequenceDiagram\n    participant DBT\n    participant Tool\n    participant Repository\n    DBT--\u003e\u003eRepository: Get truststore from Repository (public keys of trusted tool authors)\n    DBT--\u003e\u003eRepository: What's latest version of dbt, and what's its sha256 checksum?\n    loop DBT Integrity Check\n        DBT-\u003e\u003eDBT: Calculate my own checksum\n        DBT-\u003e\u003eDBT: Compare calculated checksum against downloaded checksum\n        DBT-\u003e\u003eDBT: Verify signature of DBT itself\n    end\n    Note over DBT,Repository: If validation fails, download the latest version.\u003cbr\u003eValidate that, and if it passes, execute it with the original arguments.\u003cbr\u003e The original process exits. The child takes over parent's pid.\u003cbr\u003eLather, rinse, and repeat.\n    DBT--\u003e\u003eRepository: Is there a tool called \u003ctool name\u003e?\n    DBT--\u003e\u003eRepository: What's the latest version of \u003ctool name\u003e, and what's its sha256 checksum?\n    loop Tool Integrity Check\n        DBT-\u003e\u003eTool: Is \u003ctool name\u003e already on disk?\n        Note over DBT,Repository: If not, download it, its checksum, and its signature\n        DBT-\u003e\u003eTool: Calculate sha256 checksum of Tool\n        DBT-\u003e\u003eTool: Compare calculated checksum against downloaded checksum\n        DBT-\u003e\u003eTool: Verify signature of Tool\n    end\n    DBT--\u003e\u003eTool: Run \u003ctool name\u003e with provided arguments\n    Note over DBT,Repository: DBT exits. Tool takes DBT's pid in the process table\n```\n\nDBT can distribute any single-file executable: Go binaries, Python tools built with PyInstaller, shell scripts with detached signatures, or anything else that compiles to a single file.\n\n## Why DBT?\n\nSoftware distribution in organizations often involves manual updates users forget, security verification that's too complex for regular use, and \"push model\" updates that break workflows.\n\nDBT implements a \"pull model\" where users get the latest version automatically, administrators get cryptographic verification and controlled distribution, and organizations avoid complex MDM infrastructure.  Users can pin to specific versions when needed (`dbt -v 1.2.3 -- tool`).\n\n## Setting Up DBT\n\nSetting up DBT for your organization requires four steps:\n\n1. **Deploy a repository** — somewhere to store your binaries\n2. **Create your signing keys** — GPG keys for artifact verification\n3. **Publish DBT itself** — get dbt and catalog onto your repository\n4. **Build your organization's installer** — a single binary that bootstraps users\n\n### Step 1: Deploy a Repository\n\nDBT needs a file server that supports HTTP GET (for downloads) and ideally HTTP PUT (for publishing).  There are several options.\n\n#### Option A: Kubernetes Reposerver (Recommended)\n\nThe built-in reposerver is a purpose-built Go HTTP server with authentication, and ships as a distroless container image.  Kustomize manifests are included in the `kubernetes/` directory.\n\n```bash\n# Deploy the base configuration\nkubectl apply -k kubernetes/base\n\n# Or create a customized overlay (recommended)\ncp -r kubernetes/overlays/example kubernetes/overlays/myenv\n# Edit kubernetes/overlays/myenv/kustomization.yaml and reposerver.json\nkubectl apply -k kubernetes/overlays/myenv\n```\n\nSet the reposerver version in your overlay's `kustomization.yaml`:\n\n```yaml\nimages:\n  - name: ghcr.io/nikogura/dbt-reposerver\n    newTag: \"3.7.16\"\n```\n\nThe base deployment creates a StatefulSet with a 10Gi PersistentVolumeClaim.  Adjust the size in your overlay to fit your artifact volume.\n\nSee `kubernetes/README.md` for the full Kubernetes deployment guide, including ingress configuration and WAF considerations.\n\n#### Option B: Docker\n\nRun the reposerver directly with Docker for development or small deployments:\n\n```bash\n# Run with default settings (serves /var/dbt on port 9999)\ndocker run -d -p 9999:9999 \\\n  -v /path/to/repo:/var/dbt \\\n  ghcr.io/nikogura/dbt-reposerver:latest\n\n# Run with a config file for authentication\ndocker run -d -p 9999:9999 \\\n  -v /path/to/repo:/var/dbt \\\n  -v /path/to/config.json:/etc/dbt/reposerver.json \\\n  ghcr.io/nikogura/dbt-reposerver:latest \\\n  -a 0.0.0.0 -p 9999 -r /var/dbt -f /etc/dbt/reposerver.json\n```\n\n**Command-line flags** (passed after the image name):\n- `-a`: Listen address (default: `0.0.0.0`)\n- `-p`: Listen port (default: `9999`)\n- `-r`: Server root directory (default: `/var/dbt`)\n- `-f`: Config file path (optional, required for authentication)\n\nThis is a distroless image with no shell.  Configuration is done via command-line flags, environment variables, or a config file.\n\n#### Environment Variable Configuration\n\nThe reposerver can be configured entirely via `REPOSERVER_` environment variables, removing the need for a JSON config file.  This is the idiomatic approach for container deployments.\n\nPriority order: **config file (`-f`)** \u003e **CLI flags (`-a`, `-p`, `-r`)** \u003e **environment variables**.\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `REPOSERVER_ADDRESS` | `0.0.0.0` | Listen address |\n| `REPOSERVER_PORT` | `9999` | Listen port |\n| `REPOSERVER_ROOT` | _(empty)_ | Server root directory |\n| `REPOSERVER_AUTH_GETS` | `false` | Require auth for GET requests |\n| `REPOSERVER_AUTH_TYPE_GET` | _(empty)_ | Auth method for GET (e.g. `oidc`, `static-token`) |\n| `REPOSERVER_AUTH_TYPE_PUT` | _(empty)_ | Auth method for PUT (comma-separated for multi-auth) |\n| `REPOSERVER_IDP_FILE_GET` | _(empty)_ | Identity provider file for GET auth |\n| `REPOSERVER_IDP_FILE_PUT` | _(empty)_ | Identity provider file for PUT auth |\n| `REPOSERVER_IDP_FUNC_GET` | _(empty)_ | Identity provider function for GET auth |\n| `REPOSERVER_IDP_FUNC_PUT` | _(empty)_ | Identity provider function for PUT auth |\n| `REPOSERVER_STATIC_TOKEN_GET` | _(empty)_ | Static bearer token for GET auth |\n| `REPOSERVER_STATIC_TOKEN_PUT` | _(empty)_ | Static bearer token for PUT auth |\n| `REPOSERVER_OIDC_ISSUER_URL_GET` | _(empty)_ | OIDC issuer URL for GET |\n| `REPOSERVER_OIDC_AUDIENCES_GET` | _(empty)_ | OIDC audiences for GET (comma-separated) |\n| `REPOSERVER_OIDC_USERNAME_CLAIM_GET` | _(empty)_ | OIDC username claim for GET |\n| `REPOSERVER_OIDC_ALLOWED_GROUPS_GET` | _(empty)_ | Allowed OIDC groups for GET (comma-separated) |\n| `REPOSERVER_OIDC_SKIP_ISSUER_VERIFY_GET` | `false` | Skip OIDC issuer verification for GET |\n| `REPOSERVER_OIDC_JWKS_CACHE_GET` | `0` | JWKS cache seconds for GET |\n| `REPOSERVER_OIDC_ISSUER_URL_PUT` | _(empty)_ | OIDC issuer URL for PUT |\n| `REPOSERVER_OIDC_AUDIENCES_PUT` | _(empty)_ | OIDC audiences for PUT (comma-separated) |\n| `REPOSERVER_OIDC_USERNAME_CLAIM_PUT` | _(empty)_ | OIDC username claim for PUT |\n| `REPOSERVER_OIDC_ALLOWED_GROUPS_PUT` | _(empty)_ | Allowed OIDC groups for PUT (comma-separated) |\n| `REPOSERVER_OIDC_SKIP_ISSUER_VERIFY_PUT` | `false` | Skip OIDC issuer verification for PUT |\n| `REPOSERVER_OIDC_JWKS_CACHE_PUT` | `0` | JWKS cache seconds for PUT |\n\n**Kubernetes example — no ConfigMap needed:**\n\n```yaml\ncontainers:\n  - name: reposerver\n    image: ghcr.io/nikogura/dbt-reposerver:latest\n    env:\n      - name: REPOSERVER_ADDRESS\n        value: \"0.0.0.0\"\n      - name: REPOSERVER_PORT\n        value: \"9999\"\n      - name: REPOSERVER_ROOT\n        value: \"/var/dbt\"\n      - name: REPOSERVER_AUTH_TYPE_PUT\n        value: \"static-token\"\n      - name: REPOSERVER_STATIC_TOKEN_PUT\n        valueFrom:\n          secretKeyRef:\n            name: dbt-reposerver\n            key: publish-token\n```\n\n**Docker example:**\n\n```bash\ndocker run -d -p 9999:9999 \\\n  -v /path/to/repo:/var/dbt \\\n  -e REPOSERVER_ROOT=/var/dbt \\\n  -e REPOSERVER_AUTH_TYPE_PUT=static-token \\\n  -e REPOSERVER_STATIC_TOKEN_PUT=my-secret-token \\\n  ghcr.io/nikogura/dbt-reposerver:latest\n```\n\n#### Option C: Amazon S3\n\nUse an S3 bucket as a repository.  No server to run — publishing is done with the AWS CLI, and DBT reads directly from S3 using standard AWS credentials.\n\n```bash\n# Create the bucket\naws s3 mb s3://my-dbt-repo\n\n# S3 URLs must use virtual host format in DBT config:\n# https://my-dbt-repo.s3.us-east-1.amazonaws.com\n```\n\nS3 authentication uses your existing AWS credential configuration (`~/.aws/`, environment variables, IAM roles, or `credential_process`).\n\n#### Option D: Artifactory or Any WebDAV Server\n\nAny server that supports HTTP GET and PUT works as a DBT repository.  [Artifactory Open Source](https://www.jfrog.com/open-source), Apache with WebDAV, nginx with dav module — all are viable options.\n\n### Step 2: Secure Your Repository\n\n\u003e \"DBT is as secure as the repository you trust and how well you protect your signing keys.\"\n\nIf your repository is the reposerver (options A or B above), you should configure authentication.  The reposerver supports separate auth methods for read (GET) and write (PUT/DELETE) operations.\n\n#### Choosing an Auth Method\n\n| Method | Best For | Config Value |\n|--------|----------|--------------|\n| **SSH-OIDC** (Recommended) | Passwordless CLI auth via SSH keys + Dex — no browser, no passwords | `oidc` |\n| **Static token** | CI/CD pipelines, automated publishing | `static-token` |\n| **SSH-agent JWT** | Direct SSH key verification without an OIDC provider | `ssh-agent-file` |\n| **Basic auth (htpasswd)** | Small teams, simple setups | `basic-htpasswd` |\n| **Browser-based OIDC** | Keycloak, Okta, Auth0 (requires browser redirect — poor CLI UX) | `oidc` |\n\nYou can combine multiple methods.  For example, OIDC for user downloads and a static token for CI/CD publishing.  Separate multiple auth types with commas: `\"authTypePut\": \"static-token,oidc\"`.\n\n#### Example: Open Reads, Token-Protected Writes\n\nThe simplest production setup — anyone can download tools, but publishing requires a token:\n\n```json\n{\n  \"address\": \"0.0.0.0\",\n  \"port\": 9999,\n  \"serverRoot\": \"/var/dbt\",\n  \"authGets\": false,\n  \"authTypePut\": \"static-token\",\n  \"authOptsPut\": {\n    \"staticTokenEnv\": \"DBT_PUBLISH_TOKEN\"\n  }\n}\n```\n\nSet the `DBT_PUBLISH_TOKEN` environment variable on the reposerver container.  Clients publish using `Authorization: Bearer \u003ctoken\u003e`.\n\nThe `staticTokenEnv` field reads the token from an environment variable (recommended).  You can also use `staticToken` to set the value directly in config, but environment variables are safer for production.\n\n#### Example: OIDC for Everything\n\nFull OIDC authentication for both reads and writes, with group-based authorization for publishing:\n\n```json\n{\n  \"address\": \"0.0.0.0\",\n  \"port\": 9999,\n  \"serverRoot\": \"/var/dbt\",\n  \"authGets\": true,\n  \"authTypeGet\": \"oidc\",\n  \"authOptsGet\": {\n    \"oidc\": {\n      \"issuerUrl\": \"https://dex.example.com\",\n      \"audiences\": [\"dbt-server\"],\n      \"usernameClaimKey\": \"email\"\n    }\n  },\n  \"authTypePut\": \"oidc\",\n  \"authOptsPut\": {\n    \"oidc\": {\n      \"issuerUrl\": \"https://dex.example.com\",\n      \"audiences\": [\"dbt-server\"],\n      \"usernameClaimKey\": \"email\",\n      \"allowedGroups\": [\"dbt-publishers\"]\n    }\n  }\n}\n```\n\n**OIDC options:**\n- **issuerUrl**: OIDC provider URL (fetches `.well-known/openid-configuration` automatically)\n- **audiences**: Expected `aud` claims in tokens\n- **usernameClaimKey**: Claim to extract the username from (`sub`, `email`, `preferred_username`, or `name`)\n- **allowedGroups**: Groups authorized to access (empty = all authenticated users)\n- **requiredClaims**: Additional claims that must match exactly\n\nThis works with any OIDC provider: Dex, Keycloak, Okta, Auth0, etc.\n\n#### Example: OIDC Reads + Token Writes (Recommended for CI/CD)\n\nUsers authenticate via OIDC to download tools.  CI/CD publishes via static token:\n\n```json\n{\n  \"address\": \"0.0.0.0\",\n  \"port\": 9999,\n  \"serverRoot\": \"/var/dbt\",\n  \"authGets\": true,\n  \"authTypeGet\": \"oidc\",\n  \"authOptsGet\": {\n    \"oidc\": {\n      \"issuerUrl\": \"https://dex.example.com\",\n      \"audiences\": [\"dbt-server\"]\n    }\n  },\n  \"authTypePut\": \"static-token\",\n  \"authOptsPut\": {\n    \"staticTokenEnv\": \"DBT_PUBLISH_TOKEN\"\n  }\n}\n```\n\n#### Example: Basic Auth (htpasswd)\n\nFor small teams or environments without an identity provider:\n\n```json\n{\n  \"address\": \"0.0.0.0\",\n  \"port\": 9999,\n  \"serverRoot\": \"/var/dbt\",\n  \"authGets\": false,\n  \"authTypePut\": \"basic-htpasswd\",\n  \"authOptsPut\": {\n    \"idpFile\": \"/etc/dbt/htpasswd\"\n  }\n}\n```\n\nGenerate the htpasswd file with: `htpasswd -c /etc/dbt/htpasswd username`\n\n#### S3 Security\n\nFor S3 repositories, security is handled by AWS IAM.  Use IAM policies to control who can read from and write to the bucket.\n\n### Step 3: Create Your Signing Keys\n\nDBT verifies every binary using GPG signatures.  You need a GPG key to sign artifacts and a **truststore** containing the public key for clients to verify against.\n\n#### Generate a Signing Key\n\n```bash\n# Generate a new key (use your organization's email)\ngpg --full-generate-key\n\n# List your keys to find the key ID\ngpg --list-secret-keys --keyid-format long\n```\n\n#### Create the Truststore\n\nThe truststore is a file containing one or more PGP public keys in ASCII-armored format.  DBT clients download this file and use it to verify signatures.\n\n```bash\n# Export your public key\ngpg --armor --export your-email@example.com \u003e truststore\n\n# Multiple signers? Concatenate their public keys:\ngpg --armor --export signer1@example.com \u003e\u003e truststore\ngpg --armor --export signer2@example.com \u003e\u003e truststore\n```\n\n#### Upload the Truststore to Your Repository\n\nThe truststore must be accessible at the `truststore` path relative to your dbt repository URL.\n\n**For the reposerver (HTTP PUT):**\n\n```bash\ncurl -X PUT \\\n  -H \"Authorization: Bearer $DBT_PUBLISH_TOKEN\" \\\n  --data-binary @truststore \\\n  https://dbt.example.com/dbt/truststore\n```\n\n**For S3:**\n\n```bash\naws s3 cp truststore s3://my-dbt-repo/dbt/truststore\n```\n\n**For a plain filesystem (Docker volume, NFS, etc.):**\n\n```bash\ncp truststore /path/to/repo/dbt/truststore\n```\n\n#### Protect Your Signing Key\n\nYour signing key is the root of trust for your entire DBT deployment.  If it is compromised, an attacker can sign malicious binaries that all your users will trust.\n\n- Store the private key in a secrets manager or hardware security module\n- Never commit it to Git unencrypted\n- For CI/CD, store it as a base64-encoded secret and import it at runtime:\n\n```bash\necho -n \"$GPG_SIGNING_KEY\" | base64 -d | gpg --batch --import\n```\n\n### Step 4: Publish DBT to Your Repository\n\nYour repository needs dbt and catalog binaries before users can install anything.  The easiest way is to republish the upstream releases from GitHub.\n\n#### Repository Directory Layout\n\nThe reposerver expects this directory structure under its server root (`/var/dbt` by default):\n\n```\n/var/dbt/\n├── dbt/\n│   ├── truststore                           # GPG public keys\n│   ├── \u003cversion\u003e/\n│   │   └── \u003cos\u003e/\u003carch\u003e/\n│   │       ├── dbt                          # Binary\n│   │       ├── dbt.asc                      # GPG signature\n│   │       └── dbt.sha256                   # SHA256 checksum\n│   └── installer/\n│       └── \u003cos\u003e/\u003carch\u003e/\n│           └── dbt-installer                # Pre-built installer\n└── dbt-tools/\n    └── \u003ctoolname\u003e/\n        └── \u003cversion\u003e/\n            ├── description.txt              # Tool description (shown in catalog)\n            ├── description.txt.asc\n            └── \u003cos\u003e/\u003carch\u003e/\n                ├── \u003ctoolname\u003e               # Binary\n                ├── \u003ctoolname\u003e.asc           # GPG signature\n                ├── \u003ctoolname\u003e.sha256        # SHA256 checksum\n                └── \u003ctoolname\u003e.md5           # MD5 checksum (optional)\n```\n\n#### Path Separation: `/dbt/` vs `/dbt-tools/`\n\nThe two top-level directories serve different trust levels:\n\n- **`/dbt/`** contains dbt itself and the truststore.  These are the root of trust — if either is compromised, all downstream tool verification is meaningless.  Only administrators should have write access to this path.\n- **`/dbt-tools/`** contains tools published by developers.  Because every tool is verified against the truststore (which lives under `/dbt/`), publishing a tool does not grant trust — the tool's GPG signature must still match a key in the truststore.\n\nThis separation enables **delegated publishing**: administrators gate dbt and the truststore, while developers publish their own tools independently.  The two paths can be served from different backends entirely — different servers, different S3 buckets, or different auth policies.  The client `toolsRepository` config field controls where tools are fetched from, independent of the dbt repository URL.\n\n#### Option A: Downstream Publishing Script (Recommended)\n\nThe `scripts/publish-downstream.sh` script downloads the latest release from GitHub, signs each artifact with your GPG key, and uploads everything to your repository:\n\n```bash\n# Bearer token auth (CI/CD)\n./scripts/publish-downstream.sh \\\n  --http https://dbt.example.com \\\n  --auth bearer --token \"$DBT_PUBLISH_TOKEN\" \\\n  -y\n\n# Specific version\n./scripts/publish-downstream.sh \\\n  --http https://dbt.example.com \\\n  --auth bearer --token \"$DBT_PUBLISH_TOKEN\" \\\n  -v 3.7.16 -y\n\n# Publish to S3 instead\nexport DBT_S3_BUCKET=\"my-dbt-repo\"\nexport TOOLS_S3_BUCKET=\"my-dbt-tools-repo\"\nexport S3_REGION=\"us-east-1\"\n./scripts/publish-downstream.sh --s3 -v 3.7.16 -y\n\n# Dry run (see what would be published)\n./scripts/publish-downstream.sh \\\n  --http https://dbt.example.com \\\n  --auth bearer --token \"$DBT_PUBLISH_TOKEN\" -d\n```\n\n**Authentication options for the script:**\n\n| Method | Flag | Description |\n|--------|------|-------------|\n| Bearer token | `--auth bearer --token TOKEN` | Static token (CI/CD pipelines) |\n| OIDC | `--auth oidc --oidc-issuer URL` | Interactive authentication |\n| Basic auth | `--auth basic` | Username/password (via env vars) |\n| None | `--auth none` | No authentication (unsecured repos) |\n\n**Requirements:** `curl`, `jq`, `gpg`.  For S3: `aws` CLI.\n\nThe script publishes dbt binaries, catalog binaries, installer scripts, and (if built) pre-built installer binaries for all supported platforms.\n\n#### Option B: Manual Upload (curl)\n\nUpload individual artifacts directly:\n\n```bash\nVERSION=\"3.7.16\"\nPLATFORM=\"linux/amd64\"\n\n# Sign the binary\ngpg --detach-sign --armor dbt\n\n# Generate checksum\nsha256sum dbt | cut -d' ' -f1 \u003e dbt.sha256\n\n# Upload binary, signature, and checksum\ncurl -X PUT -H \"Authorization: Bearer $TOKEN\" --data-binary @dbt \\\n  https://dbt.example.com/dbt/$VERSION/$PLATFORM/dbt\n\ncurl -X PUT -H \"Authorization: Bearer $TOKEN\" --data-binary @dbt.asc \\\n  https://dbt.example.com/dbt/$VERSION/$PLATFORM/dbt.asc\n\ncurl -X PUT -H \"Authorization: Bearer $TOKEN\" --data-binary @dbt.sha256 \\\n  https://dbt.example.com/dbt/$VERSION/$PLATFORM/dbt.sha256\n```\n\nRepeat for each platform (`linux/amd64`, `darwin/amd64`, `darwin/arm64`) and for the catalog tool under `/dbt-tools/catalog/`.\n\n#### Option C: Gomason\n\n[Gomason](https://github.com/nikogura/gomason) can build, sign, and publish DBT from source in a single command.  This is useful if you are maintaining a fork of DBT:\n\n```bash\ngo install github.com/nikogura/gomason@latest\ngomason publish\n```\n\nGomason uses a `metadata.json` file (kept out of Git via `.gitignore`) to configure your repository URL and version.  See the Gomason documentation for details.\n\n### Step 5: Build Your Organization's Installer\n\nThe installer is a standalone binary with your organization's repository URL and authentication settings baked in.  Users download it, run it, and they're configured — no manual setup.\n\n#### Build with Make\n\n```bash\nmake build-installer \\\n  SERVER_URL=https://dbt.example.com \\\n  SERVER_NAME=prod \\\n  INSTALLER_VERSION=3.7.16\n```\n\nFor repositories with OIDC authentication:\n\n```bash\nmake build-installer \\\n  SERVER_URL=https://dbt.example.com \\\n  SERVER_NAME=prod \\\n  ISSUER_URL=https://dex.example.com \\\n  OIDC_AUDIENCE=https://dbt.example.com \\\n  OIDC_CLIENT_ID=dbt-ssh \\\n  CONNECTOR_ID=ssh \\\n  INSTALLER_VERSION=3.7.16\n```\n\nFor S3 repositories:\n\n```bash\nmake build-installer \\\n  SERVER_URL=s3://my-dbt-repo \\\n  SERVER_NAME=prod \\\n  TOOLS_URL=s3://my-dbt-tools-repo \\\n  S3_REGION=us-east-1 \\\n  INSTALLER_VERSION=3.7.16\n```\n\nThis creates platform-specific binaries in `dist/installer/`:\n\n```\ndist/installer/\n├── darwin/amd64/dbt-installer\n├── darwin/arm64/dbt-installer\n└── linux/amd64/dbt-installer\n```\n\n#### Build Variables\n\n| Variable | Required | Description |\n|----------|----------|-------------|\n| `SERVER_URL` | Yes | Base URL of dbt repository (`https://...` or `s3://...`) |\n| `SERVER_NAME` | No | Alias for this server in config (defaults to hostname) |\n| `TOOLS_URL` | No | Tools repository URL (defaults to `SERVER_URL/dbt-tools`) |\n| `ISSUER_URL` | No | OIDC issuer URL (enables OIDC auth) |\n| `OIDC_AUDIENCE` | No | OIDC token audience (defaults to `SERVER_URL`) |\n| `OIDC_CLIENT_ID` | No | OAuth2 client ID (defaults to `dbt-ssh` for SSH-OIDC) |\n| `OIDC_CLIENT_SECRET` | No | OAuth2 client secret (if required) |\n| `CONNECTOR_ID` | No | OIDC connector ID (`ssh` for SSH-OIDC with Dex) |\n| `S3_REGION` | No | AWS region for S3 (auto-detected if not set) |\n| `INSTALLER_VERSION` | No | Version string embedded in the installer |\n\n#### Distribute the Installer\n\nPublish the installer binaries to your repository (the downstream script does this automatically), or distribute them however makes sense for your organization — GitHub releases, internal downloads page, etc.\n\nUsers install by downloading and running:\n\n```bash\ncurl -O https://dbt.example.com/dbt/installer/linux/amd64/dbt-installer\nchmod +x dbt-installer\n./dbt-installer\n```\n\nThe installer:\n1. Authenticates to your repository (prompts for OIDC username if configured)\n2. Downloads and verifies the latest dbt binary\n3. Installs dbt to `~/.local/bin/dbt`\n4. Creates `~/.dbt/conf/dbt.json` with your server configuration\n5. Offers to add `~/.local/bin` to the user's shell profile\n\n#### Build from Source (Alternative)\n\nUsers can also install from source without the installer:\n\n```bash\ngit clone https://github.com/nikogura/dbt.git\ncd dbt\ngo build -o dbt ./cmd/dbt\ngo build -o catalog ./cmd/catalog\n```\n\nThis requires manual configuration of `~/.dbt/conf/dbt.json` (see [Client Configuration](#client-configuration)).\n\n## Using DBT\n\nOnce installed, users interact with dbt like this:\n\n```bash\n# List available tools\ndbt catalog list\n\n# Run a tool\ndbt -- mytool arg1 arg2\n\n# Run a tool with flags (-- separates dbt flags from tool flags)\ndbt -- mytool --verbose file.txt\n\n# Use a specific tool version\ndbt -v 1.2.3 -- mytool --help\n\n# Verbose dbt output (for debugging)\ndbt -V -- mytool file.txt\n\n# Select a specific server (multi-server config)\ndbt -s dev -- catalog list\n\n# Offline mode (use cached tools)\ndbt -o -- mytool file.txt\n```\n\nIf your tool has no flags, only positional arguments, you can omit the `--`:\n\n```bash\ndbt mytool file.txt\n```\n\nDBT checks for updates on every invocation by default.  When the repository is unreachable, it falls back to cached tools.\n\n## Publishing Your Own Tools\n\nAny single-file executable can be distributed through DBT.  The process is:\n\n1. **Build** your tool for each target platform\n2. **Sign** each binary with your GPG key\n3. **Generate checksums** for each binary\n4. **Upload** the binary, signature, checksum, and a description file to your repository\n\n### Manual Publishing (curl)\n\nBuild your tool for each platform, then sign and upload:\n\n```bash\n# Sign\ngpg --detach-sign --armor mytool\n\n# Checksum\nsha256sum mytool | cut -d' ' -f1 \u003e mytool.sha256\n\n# Upload (repeat for each platform)\ncurl -X PUT -H \"Authorization: Bearer $TOKEN\" \\\n  --data-binary @mytool \\\n  https://dbt.example.com/dbt-tools/mytool/1.0.0/linux/amd64/mytool\n\ncurl -X PUT -H \"Authorization: Bearer $TOKEN\" \\\n  --data-binary @mytool.asc \\\n  https://dbt.example.com/dbt-tools/mytool/1.0.0/linux/amd64/mytool.asc\n\ncurl -X PUT -H \"Authorization: Bearer $TOKEN\" \\\n  --data-binary @mytool.sha256 \\\n  https://dbt.example.com/dbt-tools/mytool/1.0.0/linux/amd64/mytool.sha256\n\n# Upload the tool description (shown in `dbt catalog list`)\necho \"My custom tool for doing things\" | curl -X PUT \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  --data-binary @- \\\n  https://dbt.example.com/dbt-tools/mytool/1.0.0/description.txt\n```\n\n### Using Gomason\n\nFor Go projects, [Gomason](https://github.com/nikogura/gomason) can handle the entire build-sign-publish pipeline:\n\n```bash\ngo install github.com/nikogura/gomason@latest\ngomason publish\n```\n\n### Using Boilerplate\n\nThe [Boilerplate](https://github.com/nikogura/boilerplate) project generates working project stubs with proper DBT integration:\n\n```bash\ngo install github.com/nikogura/boilerplate@latest\nboilerplate\n```\n\n### Ensuring Your Public Key is in the Truststore\n\nFor users to run your tool, your GPG public key must be in the repository's truststore.  If it's not already there:\n\n```bash\n# Export your public key\ngpg --armor --export your-email@example.com \u003e my-key.asc\n\n# Append to existing truststore\ncurl -s https://dbt.example.com/dbt/truststore \u003e truststore\ncat my-key.asc \u003e\u003e truststore\n\n# Upload the updated truststore\ncurl -X PUT -H \"Authorization: Bearer $TOKEN\" \\\n  --data-binary @truststore \\\n  https://dbt.example.com/dbt/truststore\n```\n\n## Client Configuration\n\nDBT uses a config file at `~/.dbt/conf/dbt.json`, created automatically by the installer.  If you need to configure it manually:\n\n### Multi-Server Configuration (Recommended)\n\n```json\n{\n  \"servers\": {\n    \"prod\": {\n      \"repository\": \"https://dbt.prod.example.com/dbt\",\n      \"truststore\": \"https://dbt.prod.example.com/dbt/truststore\",\n      \"toolsRepository\": \"https://dbt.prod.example.com/dbt-tools\",\n      \"authType\": \"oidc\",\n      \"issuerUrl\": \"https://dex.example.com\",\n      \"oidcAudience\": \"https://dbt.prod.example.com\",\n      \"oidcClientId\": \"dbt-ssh\",\n      \"oidcUsername\": \"jdoe\",\n      \"connectorId\": \"ssh\"\n    },\n    \"dev\": {\n      \"repository\": \"https://dbt.dev.example.com/dbt\",\n      \"truststore\": \"https://dbt.dev.example.com/dbt/truststore\",\n      \"toolsRepository\": \"https://dbt.dev.example.com/dbt-tools\"\n    },\n    \"s3\": {\n      \"repository\": \"https://my-bucket.s3.us-east-1.amazonaws.com\",\n      \"truststore\": \"https://my-bucket.s3.us-east-1.amazonaws.com/truststore\",\n      \"toolsRepository\": \"https://my-tools-bucket.s3.us-east-1.amazonaws.com\"\n    }\n  },\n  \"defaultServer\": \"prod\"\n}\n```\n\n**Server selection priority:**\n1. CLI flag: `dbt -s dev -- catalog list`\n2. Environment variable: `DBT_SERVER=dev dbt -- catalog list`\n3. Config default: `defaultServer` field\n4. First server in the map\n\n#### Per-Server Fields\n\n| Field | Description |\n|-------|-------------|\n| `repository` | URL of the dbt binary repository |\n| `truststore` | URL containing public keys of trusted authors |\n| `toolsRepository` | URL where tools are stored |\n| `authType` | Set to `\"oidc\"` to enable OIDC authentication |\n| `issuerUrl` | OIDC provider URL for token exchange |\n| `oidcAudience` | Target audience for OIDC tokens |\n| `oidcClientId` | OAuth2 client ID |\n| `oidcClientSecret` | OAuth2 client secret (if required) |\n| `oidcUsername` | Username for OIDC authentication |\n| `connectorId` | Connector ID (e.g., `\"ssh\"` for Dex SSH-OIDC) |\n\n### Legacy Single-Server Configuration\n\nThe legacy format is still supported for backward compatibility:\n\n```json\n{\n  \"dbt\": {\n    \"repository\": \"https://your-repo.com/dbt\",\n    \"truststore\": \"https://your-repo.com/dbt/truststore\"\n  },\n  \"tools\": {\n    \"repository\": \"https://your-repo.com/dbt-tools\"\n  },\n  \"username\": \"\",\n  \"password\": \"\",\n  \"usernamefunc\": \"echo $USERNAME\",\n  \"passwordfunc\": \"echo $PASSWORD\"\n}\n```\n\n### OIDC Client Authentication\n\nDBT supports two OIDC authentication flows:\n\n**SSH-OIDC (Dex with SSH connector):** DBT creates a JWT signed by your SSH key (via ssh-agent), then exchanges it with Dex for an OIDC token via RFC 8693 token exchange.  This requires no browser — authentication happens entirely on the command line.\n\n```json\n{\n  \"authType\": \"oidc\",\n  \"issuerUrl\": \"https://dex.example.com\",\n  \"oidcAudience\": \"dbt-server\",\n  \"connectorId\": \"ssh\"\n}\n```\n\nThe `connectorId` field routes the token exchange to Dex's SSH connector.  Set it to `\"ssh\"` when using Dex, or omit it for other OIDC providers that support RFC 8693 natively.\n\n**Standard OIDC (Keycloak, Okta, etc.):** For providers that support RFC 8693 token exchange without a connector:\n\n```json\n{\n  \"authType\": \"oidc\",\n  \"issuerUrl\": \"https://keycloak.example.com/realms/myrealm\",\n  \"oidcAudience\": \"dbt-server\"\n}\n```\n\n## Reposerver Authentication Reference\n\nComplete examples for every supported auth combination.\n\n### OIDC with Keycloak\n\n**Server:**\n```json\n{\n  \"address\": \"0.0.0.0\",\n  \"port\": 9999,\n  \"serverRoot\": \"/var/dbt\",\n  \"authGets\": true,\n  \"authTypeGet\": \"oidc\",\n  \"authOptsGet\": {\n    \"oidc\": {\n      \"issuerUrl\": \"https://keycloak.example.com/realms/myrealm\",\n      \"audiences\": [\"dbt-server\"],\n      \"usernameClaimKey\": \"preferred_username\"\n    }\n  },\n  \"authTypePut\": \"oidc\",\n  \"authOptsPut\": {\n    \"oidc\": {\n      \"issuerUrl\": \"https://keycloak.example.com/realms/myrealm\",\n      \"audiences\": [\"dbt-server\"],\n      \"usernameClaimKey\": \"preferred_username\",\n      \"allowedGroups\": [\"/dbt-publishers\"]\n    }\n  }\n}\n```\n\n**Client:**\n```json\n{\n  \"dbt\": {\n    \"repository\": \"https://dbt.example.com/dbt\",\n    \"truststore\": \"https://dbt.example.com/dbt/truststore\"\n  },\n  \"tools\": {\n    \"repository\": \"https://dbt.example.com/dbt-tools\"\n  },\n  \"authType\": \"oidc\",\n  \"issuerUrl\": \"https://keycloak.example.com/realms/myrealm\",\n  \"oidcAudience\": \"dbt-server\"\n}\n```\n\n### Mixed Auth (OIDC Reads, SSH-Agent Writes)\n\n```json\n{\n  \"address\": \"0.0.0.0\",\n  \"port\": 9999,\n  \"serverRoot\": \"/var/dbt\",\n  \"authGets\": true,\n  \"authTypeGet\": \"oidc\",\n  \"authOptsGet\": {\n    \"oidc\": {\n      \"issuerUrl\": \"https://dex.example.com\",\n      \"audiences\": [\"dbt-server\"]\n    }\n  },\n  \"authTypePut\": \"ssh-agent-file\",\n  \"authOptsPut\": {\n    \"idpFile\": \"/etc/dbt/pubkeys.json\"\n  }\n}\n```\n\n### SSH-Agent JWT (Direct Verification)\n\nSSH-agent authentication without an OIDC provider.  The reposerver verifies SSH key signatures directly against a list of authorized public keys:\n\n```json\n{\n  \"address\": \"0.0.0.0\",\n  \"port\": 9999,\n  \"serverRoot\": \"/var/dbt\",\n  \"authTypePut\": \"ssh-agent-file\",\n  \"authOptsPut\": {\n    \"idpFile\": \"/etc/dbt/pubkeys.json\"\n  }\n}\n```\n\n### Multi-Auth (Multiple Methods Simultaneously)\n\nAccept multiple auth methods for the same operation.  The reposerver tries each method in order and accepts the first one that succeeds:\n\n```json\n{\n  \"address\": \"0.0.0.0\",\n  \"port\": 9999,\n  \"serverRoot\": \"/var/dbt\",\n  \"authGets\": true,\n  \"authTypeGet\": \"static-token,oidc,basic-htpasswd\",\n  \"authOptsGet\": {\n    \"staticToken\": \"read-token-value\",\n    \"oidc\": {\n      \"issuerUrl\": \"https://dex.example.com\",\n      \"audiences\": [\"dbt-server\"]\n    },\n    \"idpFile\": \"/etc/dbt/htpasswd\"\n  },\n  \"authTypePut\": \"static-token,oidc\",\n  \"authOptsPut\": {\n    \"staticTokenEnv\": \"DBT_PUBLISH_TOKEN\",\n    \"oidc\": {\n      \"issuerUrl\": \"https://dex.example.com\",\n      \"audiences\": [\"dbt-server\"],\n      \"allowedGroups\": [\"dbt-publishers\"]\n    }\n  }\n}\n```\n\n## Security Model\n\n### What DBT Verifies\n\nDBT will only execute binaries that:\n- Have a valid GPG signature from a key in the truststore\n- Pass SHA256 checksum verification\n- Were downloaded from a configured trusted repository\n\nIf any verification fails, DBT stops immediately.\n\n### Best Practices\n\n- Use separate signing keys for different trust levels\n- Enable authentication on your repository — at minimum for writes\n- Use HTTPS for all repository communication\n- Rotate signing keys periodically\n- Store signing keys in a secrets manager, not on disk\n- Restrict who can publish to the repository\n- Restrict who can update the truststore (it controls what code your users will trust)\n\n## CI/CD Integration\n\n### Automated Publishing with GitHub Actions\n\n```yaml\n- name: Import GPG key\n  run: |\n    echo -n \"${{ secrets.GPG_SIGNING_KEY }}\" | base64 -d | gpg --batch --import\n    FPR=$(gpg --list-secret-keys --with-colons | grep '^fpr:' | head -1 | cut -d: -f10)\n    echo \"${FPR}:6:\" | gpg --batch --import-ownertrust\n\n- name: Publish to reposerver\n  run: ./scripts/publish-downstream.sh --http https://dbt.example.com --auth bearer --token \"${{ secrets.DBT_PUBLISH_TOKEN }}\" -y\n  env:\n    GPG_IDENTITY: ${{ secrets.SIGNING_EMAIL }}\n```\n\n### Downstream Makefile Example\n\nFor organizations maintaining their own downstream repository:\n\n```makefile\nSERVER_URL     := https://dbt.example.com\nSERVER_NAME    := prod\nISSUER_URL     := https://dex.example.com\nOIDC_AUDIENCE  := https://dbt.example.com\nOIDC_CLIENT_ID := dbt-ssh\nCONNECTOR_ID   := ssh\n\n.PHONY: build-installer publish\n\nbuild-installer:\n\tcd /path/to/nikogura/dbt \u0026\u0026 make build-installer \\\n\t\tSERVER_URL=$(SERVER_URL) \\\n\t\tSERVER_NAME=$(SERVER_NAME) \\\n\t\tISSUER_URL=$(ISSUER_URL) \\\n\t\tOIDC_AUDIENCE=$(OIDC_AUDIENCE) \\\n\t\tOIDC_CLIENT_ID=$(OIDC_CLIENT_ID) \\\n\t\tCONNECTOR_ID=$(CONNECTOR_ID) \\\n\t\tINSTALLER_VERSION=$(INSTALLER_VERSION)\n\npublish: build-installer\n\t./scripts/publish-downstream.sh --http $(SERVER_URL) \\\n\t\t--auth oidc --oidc-issuer $(ISSUER_URL) -y\n```\n\n## Troubleshooting\n\n### Common Issues\n\n**\"No such tool\" error:**\n- Run `dbt catalog list` to see available tools\n- Verify your repository configuration in `~/.dbt/conf/dbt.json`\n\n**Signature verification failed:**\n- Ensure the truststore contains the signer's public key\n- Check that tools were signed with a key that matches the truststore\n- Verify the truststore URL is accessible\n\n**Repository unreachable:**\n- DBT can work offline with cached tools (`dbt -o -- tool`)\n- Check network connectivity and repository URL\n- Verify authentication credentials if required\n\n**Tool won't update:**\n- DBT checks for updates on each run by default\n- Use `dbt -V` for verbose output to see what's happening\n- Check repository permissions and connectivity\n\n**Permission denied:**\n- Ensure DBT binary has execute permissions\n- Check that `~/.dbt/` directory is writable\n- Verify tool cache directory permissions\n\n### Debug Mode\n\n```bash\ndbt -V -- tool args\n```\n\nThis shows repository communication, download progress, verification steps, and error details.\n\n## Advanced Topics\n\n### Process Replacement\n\nDBT uses `exec()` to run tools, replacing itself in the process table.  The tool runs as if invoked directly — no wrapper process remains.  This means tools running via DBT are indistinguishable from tools run directly.\n\n### Offline Mode\n\nWhen repositories are unreachable, DBT uses previously downloaded tools from its cache (`~/.dbt/tools/`).  Use `dbt -o` to force offline mode.\n\n### Version Pinning\n\n```bash\n# Always get latest (default)\ndbt -- tool args\n\n# Pin to specific version\ndbt -v 1.2.3 -- tool args\n```\n\n### Purging Cached Tools\n\n```bash\ndbt -- catalog purge\n```\n\n### Fork Configuration\n\nIf forking DBT for your organization:\n\n1. Fork the repository\n2. Create a `metadata.json` (kept out of Git via `.gitignore` so you can pull upstream changes)\n\nExample `metadata.json`:\n```json\n{\n  \"name\": \"dbt\",\n  \"version\": \"1.0.0\",\n  \"package\": \"github.com/your-org/dbt\",\n  \"repository\": \"https://your-dbt-repo.com/dbt\",\n  \"tool-repository\": \"https://your-dbt-repo.com/dbt-tools\"\n}\n```\n\n**Note:** S3 URLs must use virtual host format: `https://bucket.s3.region.amazonaws.com`\n\n## Building and Development\n\n### Requirements\n\n- Go 1.19+ (for building from source)\n- Linux, macOS, or Windows\n- GPG for signing (publishing only)\n\n### Build from Source\n\n```bash\ngo build -o dbt ./cmd/dbt\ngo build -o catalog ./cmd/catalog\n```\n\nWith an embedded version:\n\n```bash\nVERSION=1.2.3\ngo build -ldflags \"-X github.com/nikogura/dbt/pkg/dbt.VERSION=${VERSION}\" -o dbt ./cmd/dbt\n```\n\n### Run Tests\n\n```bash\nmake test\nmake lint\n```\n\n## Included Tools\n\n### Catalog\n\nShows available tools in your repository:\n\n```bash\ndbt catalog list\n```\n\nOutput:\n```\nCommands:\n    Command Name        Latest Version      Description\n    catalog             3.7.16             Tool for showing available DBT tools\n    reposerver          3.7.16             A tool repository server for DBT\n```\n\n### Reposerver\n\nHTTP repository server for hosting DBT tools and components:\n\n```bash\ndbt reposerver -a 0.0.0.0 -p 9999 -r /var/dbt -f /path/to/config.json\n```\n\n### Boilerplate\n\nProject template generator (maintained separately): [github.com/nikogura/boilerplate](https://github.com/nikogura/boilerplate)\n\n## License\n\nLicensed under the Apache License, Version 2.0.  See LICENSE file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnikogura%2Fdbt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnikogura%2Fdbt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnikogura%2Fdbt/lists"}