access-engine: secret-read evaluator for warden fetch checks (CUST-WP-0075)
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Container Image / build-and-push (push) Successful in 1m12s

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 3775@bnt-lap001
Assistant-Session: cfacb6a5-ad5b-4f79-ac67-053e3b0d34a3
This commit is contained in:
tegwick 2026-10-03 08:57:11 +02:00
parent 1309c093bb
commit 02b15a7f72
16 changed files with 1542 additions and 0 deletions

View file

@ -0,0 +1,84 @@
# ops-warden secret-read example (`flex-auth-ops-warden-fetch`)
Policy, registry and fixtures for ops-warden's **secret-fetch** policy check
(`check_fetch_policy` in ops-warden `src/warden/policy.py`): before
`warden access <need> --fetch/--exec` proxies a non-SSH credential read, it asks
whether `read` on `secret:<need_id>[/<domain>]` owned by `<owner_repo>` is
allowed. Opened by the-custodian bug `b792c5d0` (CUST-WP-0075): those checks
were sent to the SSH signing pin `flex-auth-ops-warden`, whose package admits
only `resource.system == "ops-warden"` and whose caller bindings know only that
system, so every other owner got 403.
| File | What it is |
| --- | --- |
| `policy_package.md` | `ops-warden.secret.read` v1, `allow_ttl: 5m`; the `catalog_lanes` block is generated |
| `registry_snapshot.json` | generated: one system per owner, one `secret:<need_id>` resource per lane |
| `policy_fixtures.yaml` | 15 fixtures: 4 allows, 11 denial branches |
| `check_request_*.json` | standalone requests for `POST /v1/check` |
| `../../values/ops-warden-fetch.yaml` | the pin; caller bindings generated, image digest set by hand after CI |
## Why a separate pin
One decision class per pin, independently rollable (FLEX-WP-0016). The server
serves one policy package per process. SSH signing (`sign` on
`ssh-certificate`, system `ops-warden`) and secret reads (`read` on `secret`,
system = owner repo) differ in action, resource type, systems and caller
bindings. Folding reads into the signing pin would redeploy the lane the
ops-bridge tunnels depend on for every catalog change.
## The rule
Allow when all hold, otherwise deny with the first failing reason:
`action == read` (`wrong_action`), `resource.type == secret`
(`wrong_resource_type`), tenant `tenant:platform` (`wrong_tenant`),
`subject.type == operator` (`wrong_subject_type`), non-empty subject id
(`missing_subject`), `context.need_id` present (`missing_need_id`) and in the
catalog set (`unknown_need`), `resource.system` a catalog owner
(`unknown_system`) and the owner of that need (`wrong_system`),
`resource.id == secret:<need_id>` or `secret:<need_id>/<context.domain>`
(`resource_need_mismatch`), `context.owner_repo == resource.system`
(`owner_repo_mismatch`).
Caller authentication is `enforce`: every owner system is bound to
`system:serviceaccount:ops-warden:ops-warden`. Another caller, an anonymous
call, or an owner system missing from the bindings is rejected with 401/403
before the package runs.
For a registered resource the registry's `type` wins over the caller's
(FLEX-DEC-2026-012), so a non-secret type only reaches the package on an
unregistered id; the package denies it either way.
## Regenerate when the catalog changes
The readable set is every ops-warden catalog entry with `status: active`,
`exec_capable: true` and `lane: secret`. After a lane is added or retired:
```bash
python3 tools/gen_ops_warden_fetch.py # rewrites the three generated files
python3 tools/gen_ops_warden_fetch.py --check # exit 1 on drift (tests/stage1.sh runs it)
go run ./cmd/flex-auth test-policy --file examples/ops-warden-fetch/policy_package.md
```
`--catalog PATH` overrides the default `~/ops-warden/registry/routing/catalog.yaml`.
A new **owner system** adds a caller binding, so it needs a pin redeploy. A new
lane under an existing owner changes only the package and registry, which are
baked into the image, so it needs a new image too (`deploy/README.md`).
## Verify
```bash
go run ./cmd/flex-auth test-policy --file examples/ops-warden-fetch/policy_package.md # 6 Rego tests, 15 fixtures
go run ./cmd/flex-auth load-registry -file examples/ops-warden-fetch/registry_snapshot.json
go test ./cmd/flex-auth -run OpsWardenFetch
```
## Not yet deployed
`values/ops-warden-fetch.yaml` carries no image digest until CI builds an image
containing this directory. The deploy steps (founder go required) are in
`workplans/ADHOC-2026-10-03.md`.
Residual (build mode, close-down checklist row 1): `subject.id` is whatever
ops-warden sends (its subject env or `operator`); it is not bound to an attended
human identity. The caller binding proves that ops-warden asked, not which
operator did.

View file

@ -0,0 +1,20 @@
{
"id": "check:ops-warden-fetch-forgejo-admin-api-token",
"subject": {
"id": "operator",
"type": "operator",
"tenant": "tenant:platform"
},
"action": "read",
"resource": {
"id": "secret:forgejo-admin-api-token",
"type": "secret",
"system": "railiance-platform",
"tenant": "tenant:platform"
},
"context": {
"need_id": "forgejo-admin-api-token",
"owner_repo": "railiance-platform",
"domain": null
}
}

View file

@ -0,0 +1,20 @@
{
"id": "check:ops-warden-fetch-openrouter-llm-connect",
"subject": {
"id": "operator",
"type": "operator",
"tenant": "tenant:platform"
},
"action": "read",
"resource": {
"id": "secret:openrouter-llm-connect",
"type": "secret",
"system": "railiance-platform",
"tenant": "tenant:platform"
},
"context": {
"need_id": "openrouter-llm-connect",
"owner_repo": "railiance-platform",
"domain": null
}
}

View file

@ -0,0 +1,20 @@
{
"id": "check:ops-warden-fetch-forgejo-admin-api-token",
"subject": {
"id": "operator",
"type": "operator",
"tenant": "tenant:platform"
},
"action": "read",
"resource": {
"id": "ssh-cert:actor/platform-steward",
"type": "ssh-certificate",
"system": "railiance-platform",
"tenant": "tenant:platform"
},
"context": {
"need_id": "forgejo-admin-api-token",
"owner_repo": "railiance-platform",
"domain": null
}
}

View file

@ -0,0 +1,20 @@
{
"id": "check:ops-warden-fetch-no-such-need",
"subject": {
"id": "operator",
"type": "operator",
"tenant": "tenant:platform"
},
"action": "read",
"resource": {
"id": "secret:no-such-need",
"type": "secret",
"system": "railiance-platform",
"tenant": "tenant:platform"
},
"context": {
"need_id": "no-such-need",
"owner_repo": "railiance-platform",
"domain": null
}
}

View file

@ -0,0 +1,20 @@
{
"id": "check:ops-warden-fetch-forgejo-admin-api-token",
"subject": {
"id": "operator",
"type": "operator",
"tenant": "tenant:platform"
},
"action": "read",
"resource": {
"id": "secret:forgejo-admin-api-token",
"type": "secret",
"system": "key-cape",
"tenant": "tenant:platform"
},
"context": {
"need_id": "forgejo-admin-api-token",
"owner_repo": "key-cape",
"domain": null
}
}

View file

@ -0,0 +1,300 @@
- id: fixture:ops-warden-fetch-allow-forgejo-admin-api-token
request:
id: check:ops-warden-fetch-forgejo-admin-api-token
subject:
id: operator
type: operator
tenant: tenant:platform
action: read
resource:
id: secret:forgejo-admin-api-token
type: secret
system: railiance-platform
tenant: tenant:platform
context:
need_id: forgejo-admin-api-token
owner_repo: railiance-platform
domain: null
expect:
effect: allow
reason: secret_read_lane_matched
- id: fixture:ops-warden-fetch-allow-openrouter-llm-connect
request:
id: check:ops-warden-fetch-openrouter-llm-connect
subject:
id: operator
type: operator
tenant: tenant:platform
action: read
resource:
id: secret:openrouter-llm-connect
type: secret
system: railiance-platform
tenant: tenant:platform
context:
need_id: openrouter-llm-connect
owner_repo: railiance-platform
domain: null
expect:
effect: allow
reason: secret_read_lane_matched
- id: fixture:ops-warden-fetch-allow-rapp-qonto-keycape-client
request:
id: check:ops-warden-fetch-rapp-qonto-keycape-client
subject:
id: operator
type: operator
tenant: tenant:platform
action: read
resource:
id: secret:rapp-qonto-keycape-client
type: secret
system: key-cape
tenant: tenant:platform
context:
need_id: rapp-qonto-keycape-client
owner_repo: key-cape
domain: null
expect:
effect: allow
reason: secret_read_lane_matched
- id: fixture:ops-warden-fetch-allow-domain-suffix
request:
id: check:ops-warden-fetch-forgejo-admin-api-token
subject:
id: operator
type: operator
tenant: tenant:platform
action: read
resource:
id: secret:forgejo-admin-api-token/infotech
type: secret
system: railiance-platform
tenant: tenant:platform
context:
need_id: forgejo-admin-api-token
owner_repo: railiance-platform
domain: infotech
expect:
effect: allow
reason: secret_read_lane_matched
- id: fixture:ops-warden-fetch-deny-unknown-need
request:
id: check:ops-warden-fetch-no-such-need
subject:
id: operator
type: operator
tenant: tenant:platform
action: read
resource:
id: secret:no-such-need
type: secret
system: railiance-platform
tenant: tenant:platform
context:
need_id: no-such-need
owner_repo: railiance-platform
domain: null
expect:
effect: deny
reason: unknown_need
- id: fixture:ops-warden-fetch-deny-not-exec-capable-need
request:
id: check:ops-warden-fetch-net-kingdom-lldap-bind-credential
subject:
id: operator
type: operator
tenant: tenant:platform
action: read
resource:
id: secret:net-kingdom-lldap-bind-credential
type: secret
system: railiance-platform
tenant: tenant:platform
context:
need_id: net-kingdom-lldap-bind-credential
owner_repo: railiance-platform
domain: null
expect:
effect: deny
reason: unknown_need
- id: fixture:ops-warden-fetch-deny-login-lane-need
request:
id: check:ops-warden-fetch-openbao-platform-admin-login
subject:
id: operator
type: operator
tenant: tenant:platform
action: read
resource:
id: secret:openbao-platform-admin-login
type: secret
system: railiance-platform
tenant: tenant:platform
context:
need_id: openbao-platform-admin-login
owner_repo: railiance-platform
domain: null
expect:
effect: deny
reason: unknown_need
- id: fixture:ops-warden-fetch-deny-wrong-system
request:
id: check:ops-warden-fetch-forgejo-admin-api-token
subject:
id: operator
type: operator
tenant: tenant:platform
action: read
resource:
id: secret:forgejo-admin-api-token
type: secret
system: key-cape
tenant: tenant:platform
context:
need_id: forgejo-admin-api-token
owner_repo: key-cape
domain: null
expect:
effect: deny
reason: wrong_system
- id: fixture:ops-warden-fetch-deny-unknown-system
request:
id: check:ops-warden-fetch-forgejo-admin-api-token
subject:
id: operator
type: operator
tenant: tenant:platform
action: read
resource:
id: secret:forgejo-admin-api-token
type: secret
system: secrets-engine
tenant: tenant:platform
context:
need_id: forgejo-admin-api-token
owner_repo: secrets-engine
domain: null
expect:
effect: deny
reason: unknown_system
- id: fixture:ops-warden-fetch-deny-non-secret-type
request:
id: check:ops-warden-fetch-forgejo-admin-api-token
subject:
id: operator
type: operator
tenant: tenant:platform
action: read
resource:
id: secret:forgejo-admin-api-token
type: ssh-certificate
system: railiance-platform
tenant: tenant:platform
context:
need_id: forgejo-admin-api-token
owner_repo: railiance-platform
domain: null
expect:
effect: deny
reason: wrong_resource_type
- id: fixture:ops-warden-fetch-deny-wrong-action
request:
id: check:ops-warden-fetch-forgejo-admin-api-token
subject:
id: operator
type: operator
tenant: tenant:platform
action: write
resource:
id: secret:forgejo-admin-api-token
type: secret
system: railiance-platform
tenant: tenant:platform
context:
need_id: forgejo-admin-api-token
owner_repo: railiance-platform
domain: null
expect:
effect: deny
reason: wrong_action
- id: fixture:ops-warden-fetch-deny-wrong-tenant
request:
id: check:ops-warden-fetch-forgejo-admin-api-token
subject:
id: operator
type: operator
tenant: tenant:acme
action: read
resource:
id: secret:forgejo-admin-api-token
type: secret
system: railiance-platform
tenant: tenant:acme
context:
need_id: forgejo-admin-api-token
owner_repo: railiance-platform
domain: null
expect:
effect: deny
reason: wrong_tenant
- id: fixture:ops-warden-fetch-deny-wrong-subject-type
request:
id: check:ops-warden-fetch-forgejo-admin-api-token
subject:
id: operator
type: agt
tenant: tenant:platform
action: read
resource:
id: secret:forgejo-admin-api-token
type: secret
system: railiance-platform
tenant: tenant:platform
context:
need_id: forgejo-admin-api-token
owner_repo: railiance-platform
domain: null
expect:
effect: deny
reason: wrong_subject_type
- id: fixture:ops-warden-fetch-deny-resource-need-mismatch
request:
id: check:ops-warden-fetch-forgejo-admin-api-token
subject:
id: operator
type: operator
tenant: tenant:platform
action: read
resource:
id: secret:openrouter-llm-connect
type: secret
system: railiance-platform
tenant: tenant:platform
context:
need_id: forgejo-admin-api-token
owner_repo: railiance-platform
domain: null
expect:
effect: deny
reason: resource_need_mismatch
- id: fixture:ops-warden-fetch-deny-owner-repo-mismatch
request:
id: check:ops-warden-fetch-forgejo-admin-api-token
subject:
id: operator
type: operator
tenant: tenant:platform
action: read
resource:
id: secret:forgejo-admin-api-token
type: secret
system: railiance-platform
tenant: tenant:platform
context:
need_id: forgejo-admin-api-token
owner_repo: key-cape
domain: null
expect:
effect: deny
reason: owner_repo_mismatch

View file

@ -0,0 +1,246 @@
---
id: ops-warden.secret.read
name: Ops-Warden secret read (catalog fetch lanes)
namespace: ops-warden:secret-read
version: v1
status: ready
package: flexauth.ops_warden.secret_read
allow_ttl: 5m
actions:
- read
owner: team:platform-security
fixtures:
- policy_fixtures.yaml
caring:
profile: caring-0.4.0-rc2
enforce: false
canonical_roles:
- Operator
organization_relations:
- ServiceProvider
scopes:
- level: Platform
id: platform:secret-read
tenant: tenant:platform
planes:
- Secret
- Audit
capabilities:
- View
- Use
exposure_modes:
- SecretMaterial
conditions:
- PurposeBound
- TimeLimited
- Logged
restrictions:
- PrivilegeEscalationBlocked
activation:
mode: local
metadata:
source: examples/ops-warden-fetch/policy_package.md
generator: tools/gen_ops_warden_fetch.py
catalog: ops-warden/registry/routing/catalog.yaml
origin: CUST-WP-0075 (bug b792c5d0)
---
# Ops-Warden Secret Read
ops-warden's `warden access <need> --fetch/--exec` asks this package, before it
proxies a non-SSH credential read, whether `read` on `secret:<need_id>` owned by
`<owner_repo>` is allowed (ops-warden `src/warden/policy.py`
`check_fetch_policy`). ops-warden is the conduit, never the owner; the owner
system is the lane's `owner_repo`, and no secret value is in the request.
The readable set is **not authored here**. `catalog_lanes` maps each need id to
its owner system and is generated from ops-warden's routing catalog: every entry
with `status: active`, `exec_capable: true` and `lane: secret`. Regenerate with
`python3 tools/gen_ops_warden_fetch.py`; `--check` reports drift.
The set lives in the package rather than being read from registry attributes so
that a caller cannot assert its way onto a lane the registry does not know (the
engine passes caller attributes through for unregistered resources,
FLEX-DEC-2026-012).
Who may ask is enforced before this package runs: the pin's caller bindings map
every owner system to the ops-warden ServiceAccount, in `enforce` mode, so any
other caller gets HTTP 403 and an owner system absent from the bindings gets 403
as well. The package repeats the system check as `unknown_system` /
`wrong_system` for offline evaluation and defence in depth.
## Rules
```rego
import future.keywords.if
import future.keywords.in
# BEGIN GENERATED catalog_lanes (tools/gen_ops_warden_fetch.py; do not edit by hand)
catalog_lanes := {
"agent-harness-forgejo-deploy": "railiance-platform",
"binky-company-email-imap": "railiance-platform",
"binky-qonto-api": "railiance-platform",
"email-connect-transactional": "railiance-platform",
"forgejo-admin-api-token": "railiance-platform",
"issue-core-ingestion-api-key": "railiance-platform",
"openrouter-llm-connect": "railiance-platform",
"policy-nexus-forgejo-source-read": "railiance-platform",
"railiance-backup-offsite-lane": "railiance-platform",
"rapp-qonto-keycape-client": "key-cape",
"reuse-surface-hub-write-token": "railiance-platform",
"whynot-design-npm-publish": "railiance-platform",
}
# END GENERATED catalog_lanes
catalog_systems := {system | system := catalog_lanes[_]}
decision := {"effect": "allow", "reason": "secret_read_lane_matched"} if {
allowed
} else := {"effect": "deny", "reason": first_denial} if {
true
}
allowed if {
input.action == "read"
input.resource.type == "secret"
effective_tenant == "tenant:platform"
input.subject.type == "operator"
has_subject_id
need_known
catalog_lanes[need_id] == input.resource.system
resource_id_matches_need
context_owner_matches
}
default need_id := ""
need_id := input.context.need_id if {
is_string(input.context.need_id)
}
need_known if {
need_id != ""
catalog_lanes[need_id]
}
has_subject_id if {
is_string(input.subject.id)
input.subject.id != ""
}
default effective_tenant := ""
effective_tenant := input.tenant if {
is_string(input.tenant)
input.tenant != ""
} else := input.resource.tenant if {
is_string(input.resource.tenant)
input.resource.tenant != ""
} else := input.subject.tenant if {
is_string(input.subject.tenant)
input.subject.tenant != ""
}
# warden sends secret:<need_id>, or secret:<need_id>/<domain> when a domain is set.
resource_id_matches_need if {
not has_domain
input.resource.id == sprintf("secret:%s", [need_id])
}
resource_id_matches_need if {
has_domain
input.resource.id == sprintf("secret:%s/%s", [need_id, input.context.domain])
}
has_domain if {
is_string(input.context.domain)
input.context.domain != ""
}
context_owner_matches if {
input.context.owner_repo == input.resource.system
}
default first_denial := "no_matching_rule"
first_denial := "wrong_action" if {
input.action != "read"
} else := "wrong_resource_type" if {
input.resource.type != "secret"
} else := "wrong_tenant" if {
effective_tenant != "tenant:platform"
} else := "wrong_subject_type" if {
input.subject.type != "operator"
} else := "missing_subject" if {
not has_subject_id
} else := "missing_need_id" if {
need_id == ""
} else := "unknown_need" if {
not need_known
} else := "unknown_system" if {
not input.resource.system in catalog_systems
} else := "wrong_system" if {
catalog_lanes[need_id] != input.resource.system
} else := "resource_need_mismatch" if {
not resource_id_matches_need
} else := "owner_repo_mismatch" if {
not context_owner_matches
}
```
## Tests
```rego test
package flexauth.ops_warden.secret_read_test
import future.keywords.if
import data.flexauth.ops_warden.secret_read
forgejo := {
"subject": {"id": "operator", "type": "operator", "tenant": "tenant:platform"},
"action": "read",
"resource": {
"id": "secret:forgejo-admin-api-token",
"type": "secret",
"system": "railiance-platform",
"tenant": "tenant:platform"
},
"context": {"need_id": "forgejo-admin-api-token", "owner_repo": "railiance-platform", "domain": null}
}
test_forgejo_admin_read_allowed if {
secret_read.decision.effect == "allow" with input as forgejo
}
test_domain_suffix_allowed if {
secret_read.decision.effect == "allow" with input as object.union(forgejo, {
"resource": object.union(forgejo.resource, {"id": "secret:forgejo-admin-api-token/infotech"}),
"context": object.union(forgejo.context, {"domain": "infotech"}),
})
}
test_unknown_need_denied if {
secret_read.decision.reason == "unknown_need" with input as object.union(forgejo, {
"resource": object.union(forgejo.resource, {"id": "secret:no-such-need"}),
"context": object.union(forgejo.context, {"need_id": "no-such-need"}),
})
}
test_unknown_system_denied if {
secret_read.decision.reason == "unknown_system" with input as object.union(forgejo, {
"resource": object.union(forgejo.resource, {"system": "ops-warden"}),
"context": object.union(forgejo.context, {"owner_repo": "ops-warden"}),
})
}
test_wrong_action_denied if {
secret_read.decision.reason == "wrong_action" with input as object.union(forgejo, {"action": "write"})
}
test_spoofed_domain_denied if {
secret_read.decision.reason == "resource_need_mismatch" with input as object.union(forgejo, {
"resource": object.union(forgejo.resource, {"id": "secret:forgejo-admin-api-token/other"}),
"context": object.union(forgejo.context, {"domain": "infotech"}),
})
}
```

View file

@ -0,0 +1,256 @@
{
"systems": [
{
"id": "key-cape",
"name": "key-cape secrets read through ops-warden",
"resource_types": [
{
"name": "secret",
"scope_level": "Resource",
"planes": [
"Secret",
"Audit"
]
}
],
"actions": [
{
"name": "read",
"capabilities": [
"View",
"Use"
],
"planes": [
"Secret",
"Audit"
],
"exposure_modes": [
"SecretMaterial"
]
}
],
"caring_profiles": [
"caring-0.4.0-rc2"
],
"metadata": {
"tenant": "tenant:platform",
"conduit": "ops-warden",
"generated_by": "tools/gen_ops_warden_fetch.py"
}
},
{
"id": "railiance-platform",
"name": "railiance-platform secrets read through ops-warden",
"resource_types": [
{
"name": "secret",
"scope_level": "Resource",
"planes": [
"Secret",
"Audit"
]
}
],
"actions": [
{
"name": "read",
"capabilities": [
"View",
"Use"
],
"planes": [
"Secret",
"Audit"
],
"exposure_modes": [
"SecretMaterial"
]
}
],
"caring_profiles": [
"caring-0.4.0-rc2"
],
"metadata": {
"tenant": "tenant:platform",
"conduit": "ops-warden",
"generated_by": "tools/gen_ops_warden_fetch.py"
}
}
],
"resource_manifests": [
{
"id": "ops-warden-fetch-key-cape",
"system": "key-cape",
"resources": [
{
"id": "secret:rapp-qonto-keycape-client",
"type": "secret",
"labels": [
"ops-warden-fetch",
"lane:secret"
],
"owner": "repo:key-cape",
"attributes": {
"need_id": "rapp-qonto-keycape-client",
"catalog_lane": "secret"
}
}
]
},
{
"id": "ops-warden-fetch-railiance-platform",
"system": "railiance-platform",
"resources": [
{
"id": "secret:agent-harness-forgejo-deploy",
"type": "secret",
"labels": [
"ops-warden-fetch",
"lane:secret"
],
"owner": "repo:railiance-platform",
"attributes": {
"need_id": "agent-harness-forgejo-deploy",
"catalog_lane": "secret"
}
},
{
"id": "secret:binky-company-email-imap",
"type": "secret",
"labels": [
"ops-warden-fetch",
"lane:secret"
],
"owner": "repo:railiance-platform",
"attributes": {
"need_id": "binky-company-email-imap",
"catalog_lane": "secret"
}
},
{
"id": "secret:binky-qonto-api",
"type": "secret",
"labels": [
"ops-warden-fetch",
"lane:secret"
],
"owner": "repo:railiance-platform",
"attributes": {
"need_id": "binky-qonto-api",
"catalog_lane": "secret"
}
},
{
"id": "secret:email-connect-transactional",
"type": "secret",
"labels": [
"ops-warden-fetch",
"lane:secret"
],
"owner": "repo:railiance-platform",
"attributes": {
"need_id": "email-connect-transactional",
"catalog_lane": "secret"
}
},
{
"id": "secret:forgejo-admin-api-token",
"type": "secret",
"labels": [
"ops-warden-fetch",
"lane:secret"
],
"owner": "repo:railiance-platform",
"attributes": {
"need_id": "forgejo-admin-api-token",
"catalog_lane": "secret"
}
},
{
"id": "secret:issue-core-ingestion-api-key",
"type": "secret",
"labels": [
"ops-warden-fetch",
"lane:secret"
],
"owner": "repo:railiance-platform",
"attributes": {
"need_id": "issue-core-ingestion-api-key",
"catalog_lane": "secret"
}
},
{
"id": "secret:openrouter-llm-connect",
"type": "secret",
"labels": [
"ops-warden-fetch",
"lane:secret"
],
"owner": "repo:railiance-platform",
"attributes": {
"need_id": "openrouter-llm-connect",
"catalog_lane": "secret"
}
},
{
"id": "secret:policy-nexus-forgejo-source-read",
"type": "secret",
"labels": [
"ops-warden-fetch",
"lane:secret"
],
"owner": "repo:railiance-platform",
"attributes": {
"need_id": "policy-nexus-forgejo-source-read",
"catalog_lane": "secret"
}
},
{
"id": "secret:railiance-backup-offsite-lane",
"type": "secret",
"labels": [
"ops-warden-fetch",
"lane:secret"
],
"owner": "repo:railiance-platform",
"attributes": {
"need_id": "railiance-backup-offsite-lane",
"catalog_lane": "secret"
}
},
{
"id": "secret:reuse-surface-hub-write-token",
"type": "secret",
"labels": [
"ops-warden-fetch",
"lane:secret"
],
"owner": "repo:railiance-platform",
"attributes": {
"need_id": "reuse-surface-hub-write-token",
"catalog_lane": "secret"
}
},
{
"id": "secret:whynot-design-npm-publish",
"type": "secret",
"labels": [
"ops-warden-fetch",
"lane:secret"
],
"owner": "repo:railiance-platform",
"attributes": {
"need_id": "whynot-design-npm-publish",
"catalog_lane": "secret"
}
}
]
}
],
"tenants": [
{
"id": "tenant:platform",
"name": "Platform Tenant"
}
]
}