feat(backend-gcp): v0.3 Phase 1 — Google Cloud Secret Manager backend#44
Merged
TechAlchemistX merged 1 commit intomainfrom Apr 19, 2026
Merged
feat(backend-gcp): v0.3 Phase 1 — Google Cloud Secret Manager backend#44TechAlchemistX merged 1 commit intomainfrom
TechAlchemistX merged 1 commit intomainfrom
Conversation
First v0.3 backend: `secretenv-backend-gcp` wraps the `gcloud` CLI. Strict-mode mocks from day one — no v0.2.x retrofit needed. Implementation mirrors the post-v0.2.6 aws-secrets template and uses the Phase 0 `factory_helpers` + `tokio::join!`-in-`check()` patterns. - **URI shape:** `gcp-<instance>:///<secret-name>[#version=<n>]`. Canonical `#version=<n>` directive accepts positive integers or `latest`; `latest` omits the flag so `gcloud` resolves to the newest enabled version. - **`get`:** fragment + secret-name validation happen BEFORE any `gcloud` call (v0.2.6 pattern). Shorthand, unsupported directives, extras alongside `version`, non-integer version IDs, and off-charset secret names all reject locally with enumerated-offender errors. - **`set`:** secret piped via child stdin via `--data-file=/dev/stdin` (CV-1 discipline). Fragment on `set` URI explicitly rejected — `versions add` always creates a new latest version; `#version=N` on `set` is nonsensical. - **`check()`:** Level 1 (`--version`) + Level 2 (`auth print-access-token`) + identity enrichment (`config get-value account`) run concurrently via a 3-arm `tokio::join!`. The OAuth2 bearer token from `print-access-token` is read for exit status only; `output.stdout` is dropped without interpolation into logs / errors / identity strings. A canary test (`check_level2_auth_ok_never_logs_token_body`) locks this with a sentinel token substring. - **Factory:** required `gcp_project`, optional `gcp_impersonate_service_account` (plausibility-validated as an SA email at factory time), optional `gcloud_bin` (test hook). All extraction goes through the shared `secretenv-core::factory_helpers`. - **CLI wiring:** `secretenv setup` gains `--gcp-project` + `--gcp-impersonate-service-account` flags. `backend_type_from_scheme` accepts `gcp` + `gcp-*` suffixes. `serialize_registry` adds `gcp` to the JSON arm. - **Tests:** +32 crate-level tests + 1 new setup test = +33 workspace tests (365 → 398). Full fmt / clippy (`-D warnings`) / test / deny / audit suite green. Spec: kb/wiki/backends/gcp.md. Build-log: kb/wiki/build-log.md §v0.3 Phase 1. Ships as part of the aggregate `v0.3.0` release alongside the forthcoming Azure backend. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
TechAlchemistX
added a commit
that referenced
this pull request
Apr 19, 2026
Second v0.3 backend: `secretenv-backend-azure` wraps the `az` CLI. Strict-mode mocks from day one — 36 tests. Near-mirror of the Phase 1 gcp pattern with three Azure-specific additions. - **Vault URL regex** at factory time covers all four sovereign clouds (.vault.azure.net|.vault.azure.cn|.vault.usgovcloudapi.net| .vault.microsoftazure.de) with anchored `/?$` to block path traversal (`https://foo.vault.azure.net/evil/../etc` rejected) + hyphen-edge vault-name rejection. Regex discipline was the explicit call-out in the spec — `url::Url::parse` accepts traversal shapes. - **URI shape:** `azure-<instance>:///<secret-name>[#version=<32-hex>]`. Canonical `#version=<id>` accepts 32-char lowercase hex OR `latest`; `latest` normalizes to omitting the `--version` flag (Azure CLI does NOT treat `latest` as a keyword here). - **CV-1 + encoding lock:** `set` uses `--file /dev/stdin --encoding utf-8`. The `--encoding utf-8` flag is load-bearing — the default `base64` would interpret stdin as b64-encoded and corrupt stored secrets. Dedicated drift-catch test (`set_drift_catch_rejects_missing_encoding_utf8`) declares the buggy argv form so a regression dropping the flag fails the mock. - **`--value`-leak POSITIVE drift-catch:** declared argv carries the BUGGY `--value <secret>` form. Post-fix code emits `--file /dev/stdin` instead — diverges, exit 97. Guards against future refactors "optimizing small values onto argv" (which would break CV-1). - **Cert-bound-secret detection:** `kid != null` in the `az keyvault secret show` JSON response surfaces a distinct error — v0.3 targets text secrets only. - **`check()`:** Level 1 (`az --version`, multi-line stripped) + Level 2 (`az account show --output json`, JSON parsed) via `tokio::join!`. Identity `user=<name> tenant=<id> subscription=<name> vault=<short>`. - **Soft-delete documented.** `delete` is soft (Azure default); we do NOT chain `secret purge`. Asymmetric with aws-secrets (--force-delete-without-recovery) and gcp (full delete) — platform reality. - **CLI surface:** `secretenv setup` gains `--azure-vault-url` + `--azure-tenant` + `--azure-subscription`. `backend_type_from_scheme` accepts `azure(-*)`. `serialize_registry` adds azure to the JSON arm. `setup_rejects_unknown_scheme` now uses `totally-made-up://` — all in-spec schemes now route. - Brings `regex = "1"` into the workspace as a new dep (first user). - Workspace tests 398 → 435 (+37: 36 crate + 1 setup). Gates: fmt ✅ clippy (-D warnings) ✅ test ✅ deny ✅ audit ✅. Spec: kb/wiki/backends/azure.md. Build-log: kb/wiki/build-log.md §v0.3 Phase 2. Ships as part of the aggregate `v0.3.0` release alongside gcp (Phase 1, merged as #44). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7 tasks
TechAlchemistX
added a commit
that referenced
this pull request
Apr 19, 2026
* feat(backend-azure): v0.3 Phase 2 — Azure Key Vault backend Second v0.3 backend: `secretenv-backend-azure` wraps the `az` CLI. Strict-mode mocks from day one — 36 tests. Near-mirror of the Phase 1 gcp pattern with three Azure-specific additions. - **Vault URL regex** at factory time covers all four sovereign clouds (.vault.azure.net|.vault.azure.cn|.vault.usgovcloudapi.net| .vault.microsoftazure.de) with anchored `/?$` to block path traversal (`https://foo.vault.azure.net/evil/../etc` rejected) + hyphen-edge vault-name rejection. Regex discipline was the explicit call-out in the spec — `url::Url::parse` accepts traversal shapes. - **URI shape:** `azure-<instance>:///<secret-name>[#version=<32-hex>]`. Canonical `#version=<id>` accepts 32-char lowercase hex OR `latest`; `latest` normalizes to omitting the `--version` flag (Azure CLI does NOT treat `latest` as a keyword here). - **CV-1 + encoding lock:** `set` uses `--file /dev/stdin --encoding utf-8`. The `--encoding utf-8` flag is load-bearing — the default `base64` would interpret stdin as b64-encoded and corrupt stored secrets. Dedicated drift-catch test (`set_drift_catch_rejects_missing_encoding_utf8`) declares the buggy argv form so a regression dropping the flag fails the mock. - **`--value`-leak POSITIVE drift-catch:** declared argv carries the BUGGY `--value <secret>` form. Post-fix code emits `--file /dev/stdin` instead — diverges, exit 97. Guards against future refactors "optimizing small values onto argv" (which would break CV-1). - **Cert-bound-secret detection:** `kid != null` in the `az keyvault secret show` JSON response surfaces a distinct error — v0.3 targets text secrets only. - **`check()`:** Level 1 (`az --version`, multi-line stripped) + Level 2 (`az account show --output json`, JSON parsed) via `tokio::join!`. Identity `user=<name> tenant=<id> subscription=<name> vault=<short>`. - **Soft-delete documented.** `delete` is soft (Azure default); we do NOT chain `secret purge`. Asymmetric with aws-secrets (--force-delete-without-recovery) and gcp (full delete) — platform reality. - **CLI surface:** `secretenv setup` gains `--azure-vault-url` + `--azure-tenant` + `--azure-subscription`. `backend_type_from_scheme` accepts `azure(-*)`. `serialize_registry` adds azure to the JSON arm. `setup_rejects_unknown_scheme` now uses `totally-made-up://` — all in-spec schemes now route. - Brings `regex = "1"` into the workspace as a new dep (first user). - Workspace tests 398 → 435 (+37: 36 crate + 1 setup). Gates: fmt ✅ clippy (-D warnings) ✅ test ✅ deny ✅ audit ✅. Spec: kb/wiki/backends/azure.md. Build-log: kb/wiki/build-log.md §v0.3 Phase 2. Ships as part of the aggregate `v0.3.0` release alongside gcp (Phase 1, merged as #44). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(license): switch MIT → AGPL-3.0-only + add CLA Pre-launch licensing change. v0.1 and v0.2.0 shipped under MIT (v0.2.0 is the only release currently published on crates.io / Homebrew / GH Releases). v0.3.0 and all subsequent releases ship under GNU Affero General Public License v3.0 (AGPL-3.0-only). The published MIT releases remain available under their original terms. Rationale: v0.3.0 finalizes the big-3-cloud-providers story (AWS + GCP + Azure) and the install base at the time of this change is effectively zero (zero crates.io downloads for v0.2.0 in the last 7 days; no HN launch yet). AGPLv3 closes the SaaS-wrapping loophole — §13 requires source availability to network users of modified versions — while preserving user freedom for direct installs. Paired with a Contributor License Agreement (license grant, NOT copyright assignment) to enable dual-licensing if commercial terms are ever needed. Changes: - LICENSE: full AGPLv3 text (GNU canonical, fetched via `gh api /licenses/agpl-3.0`). - Cargo.toml `[workspace.package] license`: "MIT" → "AGPL-3.0-only". Every crate inherits via `license.workspace = true`; no per-crate edit needed. - deny.toml: added "AGPL-3.0-only" to the licenses.allow list so `cargo deny check` accepts the workspace's own crates. The broader third-party allowlist (MIT / Apache-2.0 / BSD / ISC / Unicode / CC0 / Zlib / MPL-2.0) is unchanged — copy-left-strong upstreams (GPL-family) still require explicit review before adoption. - README: license badge MIT → AGPL v3; expanded License section explains the switch + the §13 SaaS-source-availability requirement + links to CLA. - CLA.md (new): the Individual Contributor License Agreement. Grants the project a perpetual, worldwide, non-exclusive, royalty-free copyright + patent license AND the right to relicense the Contribution under any terms (enables dual-licensing). Explicitly NOT a copyright assignment — contributors retain ownership. Signing via `git commit --signoff` on every commit + adding name to AUTHORS.md on first contribution. Corporate contributors contact the maintainer for a Corporate CLA. - AUTHORS.md (new): ledger of CLA-signed contributors. Seeded with the project maintainer. - CONTRIBUTING.md: new §License-and-CLA section documenting the signing mechanism + disambiguating `-s` (sign-off = CLA) from `-S` (cryptographic signature = commit-signing). Both are required. - CHANGELOG.md: flagged as a pre-launch breaking change per the policy in the session memory (install base zero + CHANGELOG documents the exception honestly). Gates: fmt ✅ clippy ✅ test ✅ (435/435) deny ✅ audit ✅. Ships on PR #45 (v0.3 Phase 2 / Azure) as part of the aggregate v0.3.0 release gate. Signed-off-by: Mandeep Patel <mandeep@techalchemist.io> Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: TechAlchemistX <mandeep@techalchemist.io> --------- Signed-off-by: Mandeep Patel <mandeep@techalchemist.io> Signed-off-by: TechAlchemistX <mandeep@techalchemist.io> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
secretenv-backend-gcpwrapsgcloud secrets versions access / add / delete+gcloud auth print-access-token. Strict-mode mocks from day one (32 tests in the crate + 1 setup test = +33 workspace tests, 365 → 398).#version=<n>directive supports positive integers +latest; version0rejected locally. Fragment + secret-name validation happen BEFORE anygcloudcall (v0.2.6 pattern).--data-file=/dev/stdin; fragment onsetURI rejected.gcloud auth print-access-tokenstdout (real OAuth2 bearer) is dropped without interpolation. Canary testcheck_level2_auth_ok_never_logs_token_bodylocks this with a sentinel substring.check()viatokio::join!(version + token + account).secretenv setup --gcp-project <p> [--gcp-impersonate-service-account <sa>];gcp(-*)accepted as a scheme; JSON registry wire-shape.0.3.0-alpha.0(no tag). Ships as part of the aggregatev0.3.0publish alongside Azure (Phase 2).Spec:
kb/wiki/backends/gcp.md. Companion Azure spec:kb/wiki/backends/azure.md.Test plan
cargo fmt --checkcargo clippy --workspace --all-targets --all-features -- -D warningscargo test --workspace— 398/398cargo deny checkcargo audit🤖 Generated with Claude Code