Correct whynot credential tenant path

This commit is contained in:
2026-06-28 01:00:12 +02:00
parent ad47a136f7
commit eb24e04b71
10 changed files with 67 additions and 48 deletions

View File

@@ -3,9 +3,9 @@ kind: credential-change-request
schema_version: 1
request_type: workload-kv-read
title: whynot-design npm publish token lane
status: approved
status: proposed
created: '2026-06-27'
updated: '2026-06-27'
updated: '2026-06-28'
requester:
agent: ops-warden
message_id: fe5b1696-8956-4bd5-9d6f-dbde1901a076
@@ -26,15 +26,22 @@ review:
decision: approved
comment: 'State Hub decision 250669d0-8475-4527-9624-cd072249f9a9: APPROVE: scoped
path and confirmed binding are acceptable'
- at: '2026-06-27T22:54:20+00:00'
reviewer: bernd.worsch
decision: scope_corrected_requires_review
comment: Corrected tenant from whynot-design to coulomb per operator clarification.
The previous approval covered platform/workloads/whynot-design/whynot-design/npm-publish
and must not be reused for the corrected platform/workloads/coulomb/whynot-design/npm-publish
scope.
target:
domain: financials
tenant: whynot-design
tenant: coulomb
workload: whynot-design
environment: production
purpose: npm package publishing through ops-warden caller-scoped fetch/exec
openbao:
mount: platform
kv_path: platform/workloads/whynot-design/whynot-design/npm-publish
kv_path: platform/workloads/coulomb/whynot-design/npm-publish
fields:
- NPM_AUTH_TOKEN
policy_name: workload-kv-read-whynot-design-npm-publish
@@ -90,7 +97,6 @@ state_hub:
related_workplan_id: RAILIANCE-WP-0006
ops_warden_reply_message_id: b175c561-7858-43f5-a309-949b0dede1b4
ops_warden_batch_message_id: fe5b1696-8956-4bd5-9d6f-dbde1901a076
decision_id: 250669d0-8475-4527-9624-cd072249f9a9
decision_api_url: http://127.0.0.1:8000/decisions/250669d0-8475-4527-9624-cd072249f9a9
decision_dashboard_url: http://127.0.0.1:3000/decisions
decision_resolved_at: '2026-06-27T22:04:32.956077Z'
superseded_decision_id: 250669d0-8475-4527-9624-cd072249f9a9
superseded_decision_resolved_at: '2026-06-27T22:04:32.956077Z'
superseded_decision_reason: tenant/workload scope corrected before secret provisioning

View File

@@ -137,12 +137,16 @@ Default pattern:
workload namespace.
3. Reference that Kubernetes Secret from the Deployment, Job, or CronJob.
Path convention:
Path convention for workload credential custody:
```text
platform/workloads/<namespace>/<service-account>/<secret-name>
platform/workloads/<tenant-or-org>/<workload>/<secret-purpose>
```
Kubernetes namespace and service-account bounds belong in the OpenBao auth role
or External Secrets binding, not in the tenant segment unless the namespace is
itself the approved workload identity.
Use CSI-mounted files only for workloads that need file references, sharper
mount boundaries, or refresh behavior that should not rewrite application
manifests. Do not use the OpenBao injector in the current deployment.

View File

@@ -103,7 +103,7 @@ A reviewer should see a concise rendered proposal:
Request: whynot-design npm publish token lane
Type: workload-kv-read
Mount/path/field:
platform/workloads/whynot-design/whynot-design/npm-publish
platform/workloads/coulomb/whynot-design/npm-publish
NPM_AUTH_TOKEN
Policy:
workload-kv-read-whynot-design-npm-publish

View File

@@ -395,7 +395,7 @@ tenant contract):
Path convention:
```text
platform/workloads/<namespace>/<service-account>/<secret-name>
platform/workloads/<tenant-or-org>/<workload>/<secret-purpose>
platform/object-storage/<consumer>
platform/databases/<consumer>
platform/operators/<purpose>

View File

@@ -25,8 +25,10 @@ Ops-warden batch follow-up:
| Item | Value |
| --- | --- |
| ops-warden catalog id | `whynot-design-npm-publish` |
| Tenant/org | `coulomb` |
| Workload/project | `whynot-design` |
| KV mount | `platform` |
| OpenBao CLI path | `platform/workloads/whynot-design/whynot-design/npm-publish` |
| OpenBao CLI path | `platform/workloads/coulomb/whynot-design/npm-publish` |
| Secret field | `NPM_AUTH_TOKEN` |
| Front-door readiness | `template`, `resolvable=false` until CCR verification |
| Read policy | `workload-kv-read-whynot-design-npm-publish` |
@@ -45,7 +47,7 @@ bao login -method=oidc -path=netkingdom role=whynot-design-workload-kv-read
Expected OpenBao fetch shape:
```bash
bao kv get -field=NPM_AUTH_TOKEN platform/workloads/whynot-design/whynot-design/npm-publish
bao kv get -field=NPM_AUTH_TOKEN platform/workloads/coulomb/whynot-design/npm-publish
```
Expected ops-warden exec shape after activation:
@@ -63,8 +65,8 @@ logging it.
The source policy grants only:
```text
read platform/data/workloads/whynot-design/whynot-design/npm-publish
read platform/metadata/workloads/whynot-design/whynot-design/npm-publish
read platform/data/workloads/coulomb/whynot-design/npm-publish
read platform/metadata/workloads/coulomb/whynot-design/npm-publish
```
It does not grant write, delete, patch, sudo, auth, sibling workload, or parent
@@ -121,7 +123,7 @@ and service account.
An approved operator must create or confirm the secret with:
```text
path: platform/workloads/whynot-design/whynot-design/npm-publish
path: platform/workloads/coulomb/whynot-design/npm-publish
field: NPM_AUTH_TOKEN
```
@@ -129,14 +131,14 @@ In the OpenBao UI, open the `platform` KV engine and create or edit the secret
at:
```text
workloads/whynot-design/whynot-design/npm-publish
workloads/coulomb/whynot-design/npm-publish
```
For policies and API checks, the same KV-v2 secret is addressed as:
```text
platform/data/workloads/whynot-design/whynot-design/npm-publish
platform/metadata/workloads/whynot-design/whynot-design/npm-publish
platform/data/workloads/coulomb/whynot-design/npm-publish
platform/metadata/workloads/coulomb/whynot-design/npm-publish
```
The OpenBao UI path does not include the `data/` or `metadata/` segment. Those
@@ -169,7 +171,7 @@ Send ops-warden only these pointers:
```text
catalog id: whynot-design-npm-publish
mount: platform
path: platform/workloads/whynot-design/whynot-design/npm-publish
path: platform/workloads/coulomb/whynot-design/npm-publish
field: NPM_AUTH_TOKEN
oidc login: bao login -method=oidc -path=netkingdom role=whynot-design-workload-kv-read
policy: workload-kv-read-whynot-design-npm-publish

View File

@@ -4,10 +4,10 @@
# path used by ops-warden's caller-scoped access lane. It does not grant list
# access to sibling workloads or mutation capabilities.
path "platform/data/workloads/whynot-design/whynot-design/npm-publish" {
path "platform/data/workloads/coulomb/whynot-design/npm-publish" {
capabilities = ["read"]
}
path "platform/metadata/workloads/whynot-design/whynot-design/npm-publish" {
path "platform/metadata/workloads/coulomb/whynot-design/npm-publish" {
capabilities = ["read"]
}

View File

@@ -19,7 +19,7 @@ Applies source-owned OpenBao workload KV read-lane policies.
Current lane:
- policy: workload-kv-read-whynot-design-npm-publish
- path: platform/workloads/whynot-design/whynot-design/npm-publish
- path: platform/workloads/coulomb/whynot-design/npm-publish
- field: NPM_AUTH_TOKEN
The script reads an OpenBao operator token from OPENBAO_TOKEN_FILE or an
@@ -131,7 +131,7 @@ Remaining live steps:
1. Confirm the whynot-design KeyCape/NetKingdom bound claim or service account.
2. Create auth/netkingdom/role/whynot-design-workload-kv-read with only the
workload-kv-read-whynot-design-npm-publish policy.
3. Provision platform/workloads/whynot-design/whynot-design/npm-publish with
3. Provision platform/workloads/coulomb/whynot-design/npm-publish with
field NPM_AUTH_TOKEN through approved OpenBao/operator custody.
4. Run positive and negative fetch verification without printing the token.
NEXT

View File

@@ -50,7 +50,7 @@ class CredentialChangeTests(unittest.TestCase):
ccr, _errors, warnings = credential_change.validate_ccr(self.sample)
rendered = credential_change.render_summary(ccr, warnings)
self.assertIn("whynot-design npm publish token lane", rendered)
self.assertIn("platform/workloads/whynot-design/whynot-design/npm-publish", rendered)
self.assertIn("platform/workloads/coulomb/whynot-design/npm-publish", rendered)
self.assertIn("whynot-design-npm-publish", rendered)
self.assertIn("readiness: template resolvable=False", rendered)
self.assertIn("approve | deny | needs_changes", rendered)
@@ -58,18 +58,15 @@ class CredentialChangeTests(unittest.TestCase):
def test_status_payload_marks_template_not_resolvable(self) -> None:
ccr, _errors, warnings = credential_change.validate_ccr(self.sample)
payload = credential_change.status_payload(ccr, warnings)
self.assertTrue(payload["apply_allowed"])
self.assertFalse(payload["apply_allowed"])
self.assertFalse(payload["frontdoor_resolvable"])
self.assertEqual(payload["access_frontdoor"]["readiness"], "template")
self.assertEqual(payload["access_frontdoor"]["catalog_id"], "whynot-design-npm-publish")
self.assertEqual(payload["apply_blockers"], [])
self.assertEqual(payload["apply_blockers"], ["apply requires status approved, got proposed"])
self.assertEqual(payload["warnings"], [])
self.assertEqual(
payload["state_hub"]["decision_id"],
"250669d0-8475-4527-9624-cd072249f9a9",
)
self.assertIsNone(payload["state_hub"]["decision_id"])
self.assertIn(
"front door requires CCR status active, got approved",
"front door requires CCR status active, got proposed",
payload["frontdoor_blockers"],
)
self.assertIn("front door is marked resolvable=false", payload["frontdoor_blockers"])
@@ -94,6 +91,11 @@ class CredentialChangeTests(unittest.TestCase):
with tempfile.TemporaryDirectory() as tmp:
copied = Path(tmp) / self.sample.name
shutil.copy2(self.sample, copied)
copied_ccr = credential_change.load_yaml(copied)
copied_ccr.setdefault("state_hub", {})[
"decision_id"
] = "250669d0-8475-4527-9624-cd072249f9a9"
credential_change.dump_yaml(copied, copied_ccr)
original = credential_change.state_hub_decision_status
try:
credential_change.state_hub_decision_status = lambda _ccr, _url: {
@@ -144,7 +146,7 @@ class CredentialChangeTests(unittest.TestCase):
rendered,
)
self.assertIn(
"# bao kv put platform/workloads/whynot-design/whynot-design/npm-publish",
"# bao kv put platform/workloads/coulomb/whynot-design/npm-publish",
rendered,
)
self.assertIn("NPM_AUTH_TOKEN=<enter-through-approved-custody>", rendered)
@@ -199,7 +201,7 @@ class CredentialChangeTests(unittest.TestCase):
def test_generated_policy_is_narrow(self) -> None:
ccr, _errors, _warnings = credential_change.validate_ccr(self.sample)
policy = credential_change.generated_policy_hcl(ccr)
self.assertIn('path "platform/data/workloads/whynot-design/whynot-design/npm-publish"', policy)
self.assertIn('path "platform/data/workloads/coulomb/whynot-design/npm-publish"', policy)
self.assertNotIn("*", policy)
self.assertNotIn("delete", policy)

View File

@@ -123,12 +123,16 @@ Kubernetes workloads, use External Secrets Operator to materialize OpenBao
values as Kubernetes Secrets. Do not use the OpenBao injector in the current
deployment.
Runtime path convention:
Runtime path convention for workload credential custody:
```text
platform/workloads/<namespace>/<service-account>/<secret-name>
platform/workloads/<tenant-or-org>/<workload>/<secret-purpose>
```
Kubernetes namespace and service-account bounds belong in the auth role or
External Secrets binding unless the namespace is itself the approved workload
identity.
ArgoCD repository credentials are operator credentials, not workload secrets,
and should live under:

View File

@@ -52,11 +52,10 @@ whynot-design.
## Proposed Contract
Use the existing workload convention documented in `docs/openbao.md` and
`docs/argocd-gitops.md`:
Use the workload credential convention documented in `docs/openbao.md`:
```text
platform/workloads/<namespace>/<service-account>/<secret-name>
platform/workloads/<tenant-or-org>/<workload>/<secret-purpose>
```
For this lane, the proposed non-secret contract is:
@@ -64,9 +63,11 @@ For this lane, the proposed non-secret contract is:
| Item | Proposed value |
| --- | --- |
| KV mount | `platform` |
| CLI path | `platform/workloads/whynot-design/whynot-design/npm-publish` |
| KV-v2 policy data path | `platform/data/workloads/whynot-design/whynot-design/npm-publish` |
| KV-v2 policy metadata path | `platform/metadata/workloads/whynot-design/whynot-design/npm-publish` |
| Tenant/org | `coulomb` |
| Workload/project | `whynot-design` |
| CLI path | `platform/workloads/coulomb/whynot-design/npm-publish` |
| KV-v2 policy data path | `platform/data/workloads/coulomb/whynot-design/npm-publish` |
| KV-v2 policy metadata path | `platform/metadata/workloads/coulomb/whynot-design/npm-publish` |
| Secret field | `NPM_AUTH_TOKEN` |
| OpenBao read policy | `workload-kv-read-whynot-design-npm-publish` |
| OIDC auth mount | `netkingdom` unless KeyCape compatibility requires `keycape` |
@@ -78,7 +79,7 @@ The expected caller-facing read shape is:
```bash
bao login -method=oidc -path=netkingdom role=whynot-design-workload-kv-read
bao kv get -field=NPM_AUTH_TOKEN platform/workloads/whynot-design/whynot-design/npm-publish
bao kv get -field=NPM_AUTH_TOKEN platform/workloads/coulomb/whynot-design/npm-publish
```
The command shape is illustrative only. Verification must avoid printing the
@@ -109,7 +110,7 @@ Acceptance:
ops-warden signing smoke.
**2026-06-27:** Reviewed the unread ops-warden request and existing
`platform/workloads/<namespace>/<service-account>/<secret-name>` convention.
`platform/workloads/<tenant-or-org>/<workload>/<secret-purpose>` convention.
Captured the proposed `whynot-design` npm publish lane above with no secret
values.
@@ -129,7 +130,7 @@ the selected `npm-publish` path.
Acceptance:
- A policy file under `openbao/policies/` defines read access to the exact
`platform/data/workloads/whynot-design/whynot-design/npm-publish` path.
`platform/data/workloads/coulomb/whynot-design/npm-publish` path.
- Metadata/list capabilities are only as broad as needed for the caller and
ops-warden fetch UX.
- The policy grants no write, delete, patch, sudo, auth, or unrelated workload
@@ -140,7 +141,7 @@ Acceptance:
**2026-06-27:** Added the concrete policy artifact at
`openbao/policies/workload-kv-read-whynot-design-npm-publish.hcl`. It grants
only `read` on the exact KV-v2 data and metadata paths for
`platform/workloads/whynot-design/whynot-design/npm-publish`; it does not grant
`platform/workloads/coulomb/whynot-design/npm-publish`; it does not grant
write/delete/list/sudo/auth or sibling workload access. Added
`scripts/openbao-apply-workload-kv-lanes.sh`,
`make openbao-workload-kv-lanes-dry-run`, and
@@ -195,7 +196,7 @@ publish token.
Acceptance:
- The path exists at
`platform/workloads/whynot-design/whynot-design/npm-publish`.
`platform/workloads/coulomb/whynot-design/npm-publish`.
- The field is named exactly `NPM_AUTH_TOKEN`.
- The token value is entered through an approved operator/OpenBao path and is
never written to Git, State Hub, chat, prompts, shell history, or workplan