EPIC: 'mosaic cred' — one governed CLI/broker for agent credential lifecycle + access (identity validation via token→certificate; fail-closed, audited) #1045
Open
opened 2026-08-04 18:30:13 +00:00 by Ghost
·
6 comments
No Branch/Tag Specified
next
refactor
fix/1257-adopt-draft-transition
docs/prd-rev1-ratification
r4-helper-port
docs/containerization-plan
feat/m4-4b-enrollment-command
feat/m4-4a-enrollment-schema
feat/m4-4-0-enrollment-design
feat/m4-3a-p1-stop-mission-task-status-writes
docs/m4-3a0-p0-map-currency
docs/c2-amendment1-company-crud
config/minimal-subset
feat/m4-1b-ii-hierarchy-commands
mosaic-cli-p1-wrappers
mosaic-cli-p1-dispatch
docs/ruling-4b-company-visibility
feat/m4-1b-hierarchy-gateway
feat/m4-1a-hierarchy-schema
feat/p6-e2e-ci-gate
feat/p5-spa-cutover
fix/1451-appservice-dockerfile-scripts
contract/onboarding-wizard
contract/custody-schema
contract/api-artifacts
fix/appservice-dockerfile-scripts
docs/t78-cli-capability-migration
contract/rollup-projection
contract/hierarchy-schema
fix/invariant-r-version-probe-retry
contract/mode-conversion
contract/tool-gateway-mapping
contract/rbac-grants
contract/identity-lifecycle
chore/s1-docs-hygiene
docs/ri-050-release-evidence
feat/webui-p4-2-settings-admin
fix/bootstrap-race
fix/teams-enumeration-scope
fix/1407-next-image-parity
docs/prd-north-star-rewrite
rescue/ms-gate-001-gatekeeper
fix/1394-recover-token-headless
fix/1390-uninstall-headless
fix/1403-n1n2-followup
fix/1391-validationpipe-boot-check
archive/salvage-20260825/wp5b-consumer-compat
wp5b-consumer-compat-2
archive/salvage-20260825/t63-fix-2648
archive/salvage-20260825/t63-fix-1389
archive/salvage-20260825/i1380ff-fix
i1380-guard
fix/send-message-exact-target-pin
t51p2wp0b
archive/ms24-fork
fix/ci-queue-wait-no-ci-merge-path
fix/credentials-gitea-seat-slots
feat/onboarding-scripts-framework
pr-1367
fix/1357-issue-view-comments
fix/1356-tea-login-fail-closed
fix/1362-harness-aware-delivery-confirm
fix/gitea-guessed-login-credential
docs/w4-document-contract
fix/d29-lease-revoke-noop
peggy/agent-send-unverified-label
fix/pr-merge-fork-ci-status
riv001-clean
docs/1216-trunk-parameterization
fix/1256-fleet-pane-path-node
fix/1017-enumeration-guard-population
fix/1182-fail-closed-launch
fix/1327-setuppath-idempotency
merge/main-into-next
ci/push-ci-comment-model
ci/pin-ci-base-image
fix/ci-queue-wait-no-status
fred/code-review-pinned-tool-rules
fred/guides-seat-identity-fleet-comms
fred/credential-fail-closed-seat-slots
fix/fleet-greenfield-blockers
feat/ri-050-qr-evaluator
archive/salvage-20260825/zane/doctor-greenfield-hint
archive/salvage-20260825/fix/ri-050-registry-secrets
archive/salvage-20260825/docs/ri-050-release-evidence
docs/ri-050-forge-docs-fastfollow
fix/ri-050-registry-secrets
test/ri-050-publish-gate-negative
archive/salvage-20260825/fix/ri-050-verify-pglite-path
fix/ri-050-verify-pglite-path
docs/ri-050-qr-probe-inventory
archive/salvage-20260825/zane/doctor-brain-home
feat/ri-050-web-stale-safety
archive/salvage-20260825/pr-1298
archive/salvage-20260825/zane/mosaic-home-support
docs/ri-050-mission-bootstrap
fix/ri-050-forge-fail-closed
feat/ri-050-publish-gate
fleet/continuation-record-2026-08-17
feat/ri-050-prd-authority
fix/ri-050-macp-fail-closed
fix/1280-identity-first-resolution
feat/w-f4-store
fix/1264-fleet-unattended-first-start
fix/1269-ci-chain-unblock
fix/1256-fleet-runtime-preflight
fix/1257-e7-draft-transition
fix/1240-fleet-transport-check
fix/1017-wire-start-agent-session
e2e-compose
fix/1241-launch-failure-visible
fix/1237-fleet-v2-dispatch
fix/1236-installer-dir-modes
fix/installer-path-and-node
feat/wf-fleet-mvp
fix/installer-provisions-node
fix/lease-test-env-isolation
release/0.0.50-integration
feat/wf5-main-merge
feat/wf5-securestorage
feat/1216-trunk-resolver
docs/1214-branch-process
docs/ia-merge-current
fix/869-lease-probe-timeout
main
feat/workspace-hygiene-tool-enforcement
feat/1080-pr-edit
fix/1179-required-security-di
feat/p3-slice0-task5-chat-runtime-router-shaggy
feat/p3-slice0-task5-chat-runtime-router
feat/wf1-composition
feat/p3-slice0-task4-web-catalog-selection
feat/lease-promotion-and-harness-isolation
ci/provision-pi-runtime
feat/p3-slice0-task3-catalog-selection
feat/p3-slice0-task2-harness-registry
adopt/965-mos-ste-writing-standard
fix/991-comment-url-scheme-normalise
feat/wf2-bundle-migration
feat/wf4-plugin-acquisition
feat/wf5-refresh-safety
fix/1145-coord-di-compiled-boot
feat/p3-slice0-task1-harness-contracts
docs/webui-phase-p-structure
feat/1150-pi-goal-extension
feat/webui-p3-chat
fix/1146-ci-queue-purpose
fix/1138-conditional-federation
feat/webui-p2-data-auth
fix/gateway-runner-image
feat/webui-p1-vite-skeleton
fix/break-c-hooks-and-web-image
docs/webui-fleet-claude-bridge-plan
fix/wizard-gateway-failure
fix/next-node-gate
fix/mosaic-init-rce
greenfield/fomo-lin
fix/1099-pipefail-wake
fix/1099-pipefail-tests
fix/1099-pipefail-sweep
fix/framework-shell-portability
fix/1043-pane-git-identity
fix/1081-issue-close-silent-comment-failure
fix/1090-enrollment-wallclock-tolerance
feat/1082-tea-stale-token-diagnostic
fix/detect-platform-silent-128-outside-repo
feat/1050-install-state-machine-red-fixture
fix/pr-merge-message-field
feat/1051-mosaic-brain-installer
feat/1045-mosaic-cred
remediation/state
fix/1056-upgrade-rollback-control-race
fix/1019-ci-queue-timeout-harness
feat/rm-02-gate-registry
fix/rm-01-reproducible-checkout
remediation/mission-setup
fix/hygiene-inert-format-gate
fix/1019-queue-guard-stdin
feat/mos-ste-writing-standard
fix/1017-enumeration-guard
fix/1007-suite-hermeticity
feat/push-guard-null-case-verification
feat/wake-preimage-provenance
mos-comms-live
docs/heartbeat-framework-layering-ms-lead
feat/869-c4-version-coupling
feat/869-c2-install-ordering-guard
feat/869-c5-doctor-activation-check
feat/per-agent-gitea-identity
fix/875-belongs-case-insensitive-slug
fix/ci-queue-wait-404-branch-absent
feat/869-c1-activation-probe
feat/869-c3-broker-supervisor
fix/865-tea-cli-comment-invocation
feat/glpi-skills
fix/860-deflake-mutator-lease-gate
fix/850-detect-platform-port-normalization
fix/856-worktree-deps-preflight
fix/835-pr-review-approve-reject-comment-flag
fix/848-truthful-evidence
fix/812-pr-review-comment
fix/849-recovery-runtime-fixture-race
docs/758-ledger-m5-001-sync
feat/834-tc-server-side-doc
feat/833-constrained-recovery-command
feat/827-gate0-probe
governance/gate0-probe3-amendment
fix/795-codex-pr-diff
fix/795-ci-base-jq
fix/795-ci-base-git
feat/791-pr3-fleet-regen
feat/791-pr2-snapshot-restore
fix/807-glpi-206
fix/808-agent-send-false-sender
feat/791-upgrade-config-protection
feat/790-mosaic-yolo-claudex-pr2
feat/790-mosaic-yolo-claudex
feat/758-v1-v2-migrator
fix/766-exact-fleet-comms
test/758-reconciler-lifecycle-gates
docs/771-kbn101-db-role-split
test/758-example-profile-dispositions
feat/758-shared-role-resolution
feat/mos-logical-identity-fencing
feat/769-kbn100-unified-schema
docs/753-kbn010-threat-gate
feat/758-roster-v2-compiler
feat/756-official-discord-plugin
fix/mos-option2-qualification-format
docs/issue-758-m0
docs/mos-option2-qualification
mos-comms
feat/tess-interaction-agent
fix/tess-docs-format
draft/mosaic-platform-prd
fix/installer-provider-gate-and-local-gateway-redis
release/mosaic-cli-0.0.37
feat/framework-constitution-alpha
fix/git-wrapper-repo-detection
fix/woodpecker-wrapper-legacy-mosaic
fix/t-a292e96f-gitea-pr-metadata
fix/gitea-pr-metadata-login-t-a292e96f
fix/t_a292e96f-pr-metadata-gitea
fix/t_3a368a52-gitea-usc-login
fix/bootstrap-hotfix
fix/populate-known-packages-list
fix/idempotent-init
archive/salvage-20260825/fix/ci-prisma-generate
archive/salvage-20260825/feat/ms-gate-001-gatekeeper-local
archive/salvage-20260825/feat/ms-gate-001-gatekeeper
archive/salvage-20260825/feat/ms24-ci-webhook
archive/salvage-20260825/fix/mission-control-proxy-routes
archive/salvage-20260825/fix/deploy-missing-env-and-networks
archive/salvage-20260825/fix/mission-control-query-provider
archive/salvage-20260825/test/ms23-p2
archive/salvage-20260825/feat/ms23-p2-audit
archive/salvage-20260825/feat/ms23-p2-roster
archive/salvage-20260825/feat/ms23-p1-proxy
archive/salvage-20260825/feat/ms23-p1-registry
archive/salvage-20260825/feat/ms23-p1-internal-provider
archive/salvage-20260825/feat/ms23-p1-interface
archive/salvage-20260825/chore/ms23-tasks-p0-complete
archive/salvage-20260825/test/ms23-p0
archive/salvage-20260825/chore/ms23-tasks-p005-006
archive/salvage-20260825/feat/ms23-p0-tree
archive/salvage-20260825/chore/ms23-tasks-p004-005
archive/salvage-20260825/feat/ms23-p0-controls
archive/salvage-20260825/chore/ms23-tasks-p0-002-004
archive/salvage-20260825/feat/ms23-p0-stream
archive/salvage-20260825/fix/ms23-prisma-rm-symlink
archive/salvage-20260825/fix/ms23-prisma-kaniko-symlink
archive/salvage-20260825/fix/ms23-prisma-script-path
archive/salvage-20260825/fix/ms23-prisma-docker-vs-ci
archive/salvage-20260825/fix/ms23-prisma-schema-local
archive/salvage-20260825/fix/ms23-prisma-api-pkg
archive/salvage-20260825/fix/ms23-prisma-cli
archive/salvage-20260825/fix/ms23-orchestrator-prisma-generate
archive/salvage-20260825/feat/ms23-p0-ingestion
archive/salvage-20260825/feat/ms23-p0-schema
archive/salvage-20260825/fix/agent-template-auth-module
archive/salvage-20260825/feat/ms22-p2-discord-router
archive/salvage-20260825/test/ms22-p2-agent-tests
archive/salvage-20260825/chore/ms22-p2-docs-update
archive/salvage-20260825/feat/ms22-p2-agent-routing
archive/salvage-20260825/chore/ms22-p2-update-docs
archive/salvage-20260825/feat/ms22-p2-user-agents
archive/salvage-20260825/feat/ms22-p2-agent-crud
archive/salvage-20260825/fix/security-audit-multer
archive/salvage-20260825/ci/portainer-deploy
archive/salvage-20260825/fix/ms21-missing-user-auth-migration
archive/salvage-20260825/infra/fix-mosaic-db-init-extensions
archive/salvage-20260825/infra/migrate-to-openbrain-db
archive/salvage-20260825/fix/flaky-queue-test
archive/salvage-20260825/fix/deploy-service-names
archive/salvage-20260825/fix/deploy-service-update
archive/salvage-20260825/fix/deploy-user-v2
archive/salvage-20260825/fix/deploy-user
archive/salvage-20260825/fix/orchestrator-widget-endpoints
archive/salvage-20260825/fix/dashboard-widget-mock-data
archive/salvage-20260825/fix/ci-glibc-image
archive/salvage-20260825/fix/dockerfile-npmrc
archive/salvage-20260825/fix/matrix-native-binary
archive/salvage-20260825/fix/kaniko-cache
archive/salvage-20260825/fix/base-image-kaniko-v2
archive/salvage-20260825/fix/base-image-kaniko
archive/salvage-20260825/feat/custom-base-image
archive/salvage-20260825/ci/pnpm-cache
archive/salvage-20260825/fix/interceptor-tests
archive/salvage-20260825/fix/kanban-tests
archive/salvage-20260825/feat/wire-chat
archive/salvage-20260825/feat/usage-widget
archive/salvage-20260825/feat/usage-widget-review
archive/salvage-20260825/fix/security-hardening
archive/salvage-20260825/fix/project-domain-attach
archive/salvage-20260825/fix/project-domain-v2
archive/salvage-20260825/feat/kanban-add-task
archive/salvage-20260825/fix/logs-page-clean
archive/salvage-20260825/fix/logs-page
archive/salvage-20260825/fix/workspace-members
archive/salvage-20260825/fix/ci-lint-632
archive/salvage-20260825/fix/lint-from-632
archive/salvage-20260825/fix/file-manager-tags
archive/salvage-20260825/fix/csrf-debug-log
archive/salvage-20260825/fix/controller-type-imports
archive/salvage-20260825/fix/system-admin-env
archive/salvage-20260825/fix/gateway-cors-trusted-origins
archive/salvage-20260825/fix/fleet-provider-form-dto-v2
archive/salvage-20260825/fix/ms22-audit
archive/salvage-20260825/fix/orchestrator-widgets
archive/salvage-20260825/fix/fleet-provider-form-dto
archive/salvage-20260825/fix/orchestrator-widgets-preexisting
archive/salvage-20260825/fix/csrf-bearer-bypass
archive/salvage-20260825/fix/ms22-missing-authmodule-imports
archive/salvage-20260825/fix/container-lifecycle-config-module
archive/salvage-20260825/fix/swarm-compose-ms22-vars
archive/salvage-20260825/chore/ms22-p1-complete
archive/salvage-20260825/feat/ms22-p1k-idle-reaper
archive/salvage-20260825/feat/ms22-p1j-docker
archive/salvage-20260825/feat/ms22-p1e-onboarding-api-work
archive/salvage-20260825/feat/ms22-p1c-config-api
archive/salvage-20260825/chore/ms22-prd-tracking
archive/salvage-20260825/feat/ms22-p1b-crypto
archive/salvage-20260825/docs/ms22-architecture
archive/salvage-20260825/feat/ms22-openclaw-docker
archive/salvage-20260825/feat/ms22-openclaw-gateway-module
archive/salvage-20260825/chore/ms21-complete
archive/salvage-20260825/chore/ms21-final-tasks-done
archive/salvage-20260825/fix/ms21-ui-001-qa
archive/salvage-20260825/feat/ms22-openclaw-docker-backup-20260301
archive/salvage-20260825/chore/ms22-phase0-complete
archive/salvage-20260825/feat/ms21-ui-teams-rbac-v3
archive/salvage-20260825/test/ms22-integration
archive/salvage-20260825/feat/ms22-ingest-clean
archive/salvage-20260825/feat/ms21-ui-users-members
archive/salvage-20260825/feat/ms22-ingest
archive/salvage-20260825/feat/ms22-task-agent
archive/salvage-20260825/chore/ms22-tasks-tracking
archive/salvage-20260825/feat/ms21-ui-teams-rbac
archive/salvage-20260825/fix/openbao-otel-cve
archive/salvage-20260825/ci/unified-pipeline
archive/salvage-20260825/feat/ms22-conversation-archive
archive/salvage-20260825/feat/ms22-agent-memory
archive/salvage-20260825/feat/ms22-findings
archive/salvage-20260825/feat/ms22-knowledge-schema
archive/salvage-20260825/chore/tasks-final
archive/salvage-20260825/chore/tasks-update
archive/salvage-20260825/feat/ms21-session-invalidation
archive/salvage-20260825/feat/ms21-rbac-settings
archive/salvage-20260825/feat/ms21-rbac
archive/salvage-20260825/feat/ms21-ui-user-dialogs
archive/salvage-20260825/feat/ms21-ui-workspace-members
archive/salvage-20260825/feat/ms21-ui-teams
archive/salvage-20260825/chore/ms21-tasks-ui-progress
archive/salvage-20260825/feat/ms21-ui-workspaces
archive/salvage-20260825/feat/ms21-ui-users
archive/salvage-20260825/chore/ms21-tasks-schema-fix
archive/salvage-20260825/feat/ms21-import-api
archive/salvage-20260825/test/ms21-migration-tests
archive/salvage-20260825/feat/ms21-teams-page
archive/salvage-20260825/feat/ms21-users-page
archive/salvage-20260825/chore/ms21-task-update-p1-p3
archive/salvage-20260825/feat/ms21-admin-module
archive/salvage-20260825/fix/websocket-reconnect
archive/salvage-20260825/merge/develop-to-main
skill-lifecycle-v1
onboarding-v1
agent-seats-v1
interactive-agent-v1
auto-apply-v1
session-fork-v1
retention-v1
mission-policy-v1
conductor-v1
workspace-capabilities-v1
sessions-v1
operator-ergonomics-v1
adapter-seam-v1
release-model-v1
mission-task-v1
config-hello-v1
poc-container-hello-v0
v0.0.39-alpha
mosaic-v0.0.31
fed-v0.2.0-m2
fed-v0.1.0-m1
mosaic-v0.0.29
mosaic-v0.0.28
mosaic-v0.0.27
mosaic-v0.0.26
mosaic-v0.0.25
mosaic-v0.0.24
v0.2.0
v0.1.0
v0.0.8
v0.0.7
v0.0.6
v0.0.5
v0.0.4
archive/ms24-fork-20260823
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
Assignees
code-be-01 (Mosaic fleet seat code-be-01)
code-be-02 (Mosaic fleet seat code-be-02)
code-dogfood-01 (Mosaic fleet seat code-dogfood-01)
code-infra-01 (Mosaic fleet seat code-infra-01)
darkwing (Mosaic fleet seat darkwing)
dewey (Mosaic fleet seat dewey)
fargo
filbert (Mosaic fleet seat filbert)
fred
gate-merge-01 (Mosaic fleet seat gate-merge-01)
happy
jason.woltje (Jason Woltje)
marcie
merge-gate
ops-01 (Mosaic fleet seat ops-01)
ops-02 (Mosaic fleet seat ops-02)
ops-03 (Mosaic fleet seat ops-03)
ops-ci-01 (Mosaic fleet seat ops-ci-01)
ops-deploy-01 (Mosaic fleet seat ops-deploy-01)
orch-01 (Mosaic fleet seat orch-01)
pepper
resume
rev-code-01
rev-code-02
rev-security-01
rev-security-02
rev-security-03 (Mosaic fleet seat rev-security-03)
rocko (Mosaic fleet seat rocko)
sanity
scooby (Scooby)
scrappy
shaggy
tiny
topher (Mosaic fleet seat topher)
velma
veronica (Mosaic fleet seat veronica)
vision
woodpecker
Clear assignees
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: mosaicstack/stack#1045
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem — credential access is scattered, and the scatter is the failure
There is no single governed tool for agent credential lifecycle and access. What exists is split across two disconnected systems and several ad-hoc scripts:
_lib/credentials.sh+credentials.json— a read-only loader for shared service credentials (load_credentials <service>→ env vars forgitea-mosaicstack,gitea-usc, portainer, authentik, woodpecker, cloudflare…). One token per service — the shared account.~/.config/mosaic/secrets/gitea-tokens/gitea-<host>-<identity>.token, resolved bygit-credential-mosaic(viaMOSAIC_GIT_IDENTITY) for git, and byget_gitea_token(detect-platform.sh) for the API path, and wired into each seat by hand.Nothing owns the per-agent lifecycle (mint → register → wire → validate → rotate → revoke) or governs per-agent access (one fail-closed, audited code path). The consequences, all observed in one night of fleet dogfooding:
MOSAIC_GIT_IDENTITY; seats reach the runtime unable to do git.git-credential-mosaicfails closed,get_gitea_tokenfalls back to the shared credential silently and authors as the owner.api-commit.pysilently fails while the shell wrappers work; every caller re-implements host detection, token lookup, UA, and fail-closed logic slightly differently.Vision —
mosaic cred: one governed entry point for credential lifecycle + accessA single CLI (growing into a broker) that owns credentials the way
mosaic-delegateowns delegation: a predictable, mandatory path that every agent and script uses instead of reading token files directly.Proposed CLI surface
Non-negotiable invariants (baked in once, not re-implemented per caller):
validateproves the credential can actually do the operation on the target repo, not just that a file exists (a token that works on one repo proves nothing about another).Agent validation — token now, certificate/broker next (the part you flagged)
mosaic credwraps the existing per-slot tokens +credentials.jsonbehind the surface above. Still bearer tokens, but ONE governed, fail-closed, audited, UA-correct code path. Subsumes #1043 (provision/wire) and #1044 (fail-closed get).mosaic credvalidates the requester before issuing anything, so an unwired/wrong agent gets a refusal, not a shared token.mosaic credbecomes a broker/daemon (Vault approle/PKI-style) that issues short-lived, narrowly-scoped, per-operation credentials. Nothing long-lived sits in a file → kills #1013, and there is no shared credential to fall back TO.Don't reinvent storage — front the backend
The stack already has an IdP (Authentik) and a secrets story (Vault, per VAULT-SECRETS.md).
mosaic credshould be the agent-facing governance + identity layer OVER whatever backend (file store now, Vault/Authentik later) — it owns the contract and the fail-closed/audit behavior, not the secret storage itself.Subsumes / relates to
mosaic cred provision/wire.getinvariant.Recommend keeping #1043/#1044 as the concrete near-term fixes and adopting THIS as the umbrella they roll up into, so the point fixes are built as the first slices of
mosaic credrather than throwaway patches.Open design decisions (operator)
Resolved requirement (operator, 2026-08-04) — pluggable backends + emergency-update UX + red-team
Scope confirmed:
mosaic credsupplies ALL external-service creds (Gitea/GitHub/Forgejo/Matrix/Discord/…) with authN + authZ screening on every request. Authentik is at most the human-identity layer; it does not hold service secrets.Backends are ADAPTERS behind one abstraction (both supported, chosen per-cred):
.vault.addr). Poor human UX (hard to unlock/see) — NOT the human-facing surface.Emergency-update UX is a first-class requirement (operator): a human must be able to rotate a credential fast, in an emergency, without Vault's UX. Resolution via the abstraction — decouple the human write-path from the agent read-path: humans update in the friendly surface (VaultWarden UI);
mosaic credbrokers agent reads and, where the agent-tier backend differs (Vault), an adapter syncs/propagates the change. So "update once in the easy place, agents pick it up" — safety AND emergency usability, not one at the cost of the other.Bootstrap (secret-zero) mechanism — MUST be red-teamed before adoption (operator): proposed anchor is systemd
LoadCredential=(web1 has systemd 252; tmpfs, unit-private$CREDENTIALS_DIRECTORY, not in env, not inherited by siblings — also mitigates #1013) delivering a short-lived signed JWT (sub=agent, scopes, exp ~minutes) thatmosaic credverifies (authN) before applying RBAC policy (authZ). This entire bootstrap chain is a REQUIRED adversarial-review item — do not adopt LoadCredential as "secure" without a red-team that tries to read another agent's credential dir, race the tmpfs, or forge/replay the JWT.Open verify items: (1) does VaultWarden expose Secrets Manager / any master-password-free machine read; (2) red-team LoadCredential; (3) JWT issuer/rotation/revocation design. Prior jarvis-session VW-API research requested via scout.
Correction (operator scoping, 2026-08-04): homelab-first, not USC
My earlier comment grounded on USC-network artifacts — that was a mis-grounding (mos-claude sits on the USC network; the deployment target is the homelab).
.vault.addrreferenced earlier is the USC Vault and may not be the homelab's — do not assume it applies.DECIDED: VaultWarden cannot back agent secrets. Vault (AppRole) or equivalent machine identity is required.
The single fact this epic was waiting on is settled, tested live against the homelab instance (not inferred from the other deployment, and not from stale notes).
1. No Secrets Manager — and it is not coming
Probed unauthenticated against the homelab VaultWarden, version 2026.6.0:
/api/config/api/secrets/api/projects/api/service-accountsfeatureStatesSo: no machine accounts, no
bwstokens, no server-enforced TTL.Why this is stronger than a single negative: the original research covered 2025.12.0; this re-probe is a build six months newer and the surface is still absent. That kills the obvious counter-hypothesis ("it will arrive in an upgrade"). Plan as though it never will.
2. Zero-knowledge blocks the fallback — architectural, instance-independent
Even via the human password-vault API:
bw login --apikeyauthenticates but yields no decryption key;bw unlockrequires the account master password to derive it. There is no way around this without an interactive human at every start.Consequence: every host would have to hold at rest, per agent, an API key pair and the master password. A broker whose bootstrap secret is the master password is not a broker — it inverts the property the broker exists to provide.
3. Consequences for this epic
bw,bws,baonorvaultis installed on the relevant hosts, and nothing fetches a secret at runtime today. This is a greenfield choice.4. Cross-links to #1044 (the fail-open)
The threat analysis records that Bitwarden/VaultWarden API-key login uses
client_credentialsand BYPASSES 2FA. Given #1044 is already a silent wrong-identity fail-open, a 2FA-bypassing credential path in the same lane deserves explicit treatment in the design — not just a note. Any adapter that can authenticate without a second factor must be scoped and audited accordingly.Open operator decisions (narrowed)
The earlier four are now effectively two, because the backend question is answered for the agent tier:
HARD CONSTRAINT ON SELF-SERVICE ROTATION: a bearer-token-only broker cannot mint downstream credentials on this Gitea
Surfaced by actually attempting it during a live credential rotation, not from docs.
Gitea will not mint a token when authenticated with
Authorization: token <tok>— it returns 401. Minting requires basic auth:Independently corroborated from the seat-provisioning path in this fleet, which hit the same wall from a different direction and adopted the same workaround: admin
Sudotoken-creation fails (missingwrite:userscope), so provisioning sets a known random password via admin edit and then mints as the user over basic auth, using a 600-perm curl config so the secret never reachespsor output. Two independent routes, one conclusion: token-based minting does not work here; basic auth does.Why this constrains the design
A broker holding only a bearer token cannot issue its own downstream credentials. So a self-service / auto-rotation design on this provider must either:
This should be settled before any phase-3 short-lived-credential work, because it decides whether the broker can rotate autonomously or always needs a privileged helper.
Worked example of the target pattern (and an anti-pattern refused in the moment)
During the rotation, the fast fix was to install a human's personal token into a service. It was refused, correctly: putting a human credential into a service is precisely the #1044 anti-pattern, and fixing one instance while committing another is not a fix.
Instead: a dedicated least-privilege token per consumer — one scoped
read:repositorybound to the single ArgoCD consumer, a separatewrite:repositoryone for a different device — each independently revocable, revoking one disturbing nothing else.The generalisation for this epic, in the reporter's words: one credential per consumer, scoped to what that consumer does, revocable without collateral. And the reason it matters is not tidiness, it is blast radius —
That is the strongest argument in this epic for per-consumer issuance: a credential that cannot be revoked in practice is not a credential you control.
⚠ CORRECTION — I cited the WRONG ESTATE's Vault. The homelab has no Vault at all.
ESTATE: HOMELAB (this epic's target).
Earlier in this issue I wrote that Vault is "already configured (
.vault.addr)" and used that to argue the agent tier could point at an existing deployment. That is wrong, and it is an estate confusion.The configured Vault is
vault.uscllc.net— the USC estate's Vault. This epic targets the homelab estate, where:vault,bao,bwnorbwsis installed on the homelab hosts (independently confirmed on both).What changes
Why this happened — worth recording, because it is a defect class
The claim was grounded on the infrastructure the reporting agent could see from its own host, which sits in the USC estate, while the target of the work is the homelab. An estate is a property of the TARGET, not of the actor, and hosts straddle — the same host pushes to homelab git while holding USC cluster access, so location proves nothing about which estate an action belongs to.
Per operator directive, every comms and infrastructure claim must now declare
ESTATE: HOMELAB/ESTATE: USC/ESTATE: CROSS (a→b). This correction is the first thing that rule caught.🔴 REVIVAL — this epic has 5 substantive comments, 4 operator decisions, and ZERO development. Naming the next slice and an owner.
Operator directive (2026-08-06): "
mosaic credis still needing collaboration and dev work with local and remote agents. There is a plan and it needs revived. I'm tired of missions getting lost. We are dogfooding the fix with Mosaic Stack."What is already settled here — do not re-litigate
vault.uscllc.netis USC. Estate corrected in-thread.curl -u '<user>:<token>' -X POST /api/v1/users/<user>/tokens.What was NOT settled and is why this stalled
No slice was ever cut, and no owner was named. The epic describes phases 1–3 and four open design decisions; nobody was asked to build the first thing. A plan with no first slice is a flag, not a conversion — the failure class this fleet spent 2026-08-05 cataloguing.
🔬 NEW EVIDENCE FROM TONIGHT'S DOGFOODING — the file store's shape is worse than the epic states
Measured across
~/.config/mosaic/secrets/gitea-tokens/(68 files):This is not per-seat oversight — it is the architecture, and it produced three separate blockers in one night, all previously diagnosed as unrelated:
secrev*seats are USC-only, so C1/#1059/#1061/#1066 have no second reviewer. Filed as a provisioning ask; it is actually this.installer-7cannot readusc/docs-developer— cross-estate, same cause.orchestratorhadpull-only onusc/docs-developerand routed a merge to another principal. (Fixed 2026-08-06 by grantingwrite; verified from its own token. The permission was a one-line fix — the missing capability was invisible until a merge needed it.)⇒ SLICE 1 — proposed, small, and it closes a live blocker
mosaic cred whoami+mosaic cred validate <identity> --host <h> [--repo <r>]— read-only, no minting, no storage changes.Why this slice first:
validatemust resolve the identity, hit the target repo, and reportadmin/push/pull— not "a file exists."Explicitly NOT in slice 1: minting, rotation, revocation, the broker, backend selection. Those inherit the four open design decisions;
whoami/validateinherit none of them.🤝 COLLABORATION — @jarvis
@jarvis — you hold a homelab Gitea identity and this epic's target is the homelab. Requesting you take the design half of slice 1 with me:
whoamireports, and what it must refuse to guess), andvalidateoutput contract — I want it to emit a write-differential per repo, so a caller can tell "this identity can push here and not there" without inferring.I will bring the measured per-estate token inventory and tonight's three blocker cases as the test corpus. Reply on this issue — the git channel is the durable one, and this mission was lost once already by living in messages.
⚠ AND THE STANDING TRAP THIS EPIC MUST NOT WALK INTO
#1057: repairing the
credentials.jsonschema drift RE-ARMS the shared-credential fallback. Measured tonight:.gitea.mosaicstackhas no flat.token(migrated) so its fallback is dead by accident;.gitea.uscstill has one, so USC's fallback is LIVE. Anymosaic credwork that touches the loader must land after #1043 makes identity-unset fail closed — never before. We are protected by a key that moved, not by a decision.