Security
Documentation Map
-
Security
-
Channel:
stable -
Source repo:
JaddaHelpifyr/jhf-pattern
Security
Auth Model
- primary operator auth:
- session cookie
pm_session
- session cookie
- supported auth-related integrations:
- Gitea OAuth
- GitHub OAuth
- GitLab OAuth
- OIDC
- development auth:
- optional dev-login path
- only appropriate when explicitly enabled
Access Control
- product writes are expected to run through authenticated operator paths
- integration configuration and revoke/bootstrap flows are privileged
- recovery actions such as restore, freeze, and unfreeze require explicit operator intent
- MCP is not a bypass path; it rides the same product contract and should remain auditable
Sensitive Data Types
- provider OAuth client secrets and tokens
- Plane API token and webhook secret
- approval shared secret
- runtime and n8n webhook targets
- database credentials
- session secret
Secret Model
- secrets are expected in runtime environment or external secret storage
- secrets must not be committed into the repository
- this repository documents required secret names but does not carry secret values
- standalone mode and integrated mode must both keep repository history free of secret material
Secret And Credential Classes
| Class | Typical values | Allowed source in standalone mode | Allowed source in integrated mode | Current Mission Control persistence | Rotation owner |
|---|---|---|---|---|---|
| session and database bootstrap | SESSION_SECRET, DATABASE_URL | runtime environment or external secret storage injected into the process | runtime environment or external secret storage injected by the shared platform layer | not persisted by Mission Control | platform or host operator |
| provider OAuth application credentials | GITEA_OAUTH_CLIENT_SECRET, GITHUB_OAUTH_CLIENT_SECRET, GITLAB_OAUTH_CLIENT_SECRET, OIDC_CLIENT_SECRET | runtime environment, or operator-saved setup state when the current settings flow stores them for the active instance | shared platform runtime injection; no Fabric-side write-back into the repo | may be mirrored in operator-controlled _control/*_oauth.json state for active setup flows | operator or platform operator |
| provider user or automation access tokens | GITEA_TOKEN, GITHUB_TOKEN, GITLAB_TOKEN or OAuth access tokens | runtime environment and operator-controlled OAuth login state | runtime environment, platform secret injection, or fresh operator re-authorization when user context is required | operator OAuth state may store active access tokens outside the repo | operator for user tokens; platform operator for automation tokens |
| workspace integration credentials | PLANE_API_TOKEN and project-scoped saved provider/Plane credentials | runtime environment or operator-saved workspace/project integration records | same as standalone until a shared attachment contract exists; no automatic takeover is implemented | Plane and provider bridge records may store credentials in workspace metadata today | operator |
| callback and webhook shared secrets | PLANE_WEBHOOK_SECRET, CLAWLEDGER_APPROVAL_SHARED_SECRET | runtime environment or external secret storage injected into runtime | runtime environment or external secret storage injected by the shared layer | not persisted by the repo; consumed from runtime settings | platform or host operator |
| outbound protected webhook targets | N8N_OPERATOR_WEBHOOK_URL, OPENCLAW_RUNTIME_DISPATCH_WEBHOOK_URL plus upstream auth material outside this repo | deployment-specific runtime environment or external secret storage | deployment-specific runtime environment or external secret storage | URL may be configured in runtime settings; upstream auth stays outside this repo | platform or host operator |
Mode Boundary
- standalone mode:
- the operator or host owner is responsible for secret sourcing, runtime injection, and revocation
- Mission Control may persist some operator-entered provider or workspace credentials in runtime state outside git history
- integrated mode:
- Fabric may discover that Mission Control needs these secret classes, but Fabric does not currently push or rotate them
- the shared platform layer may inject runtime secrets, but Mission Control does not yet implement a dedicated integrated credential handoff API
- when user-context provider access is required, operator re-authorization remains the expected path
Mode Transition Rules
- the move from standalone to integrated must not silently regenerate OAuth apps, shared secrets, or provider tokens
- an integrated deployment may reuse existing standalone secret values only through explicit operator-controlled runtime injection or re-entry
- Mission Control does not treat Fabric as a secret source of truth today
- if a credential source changes, the old value must be revoked or rotated by the responsible operator; Mission Control does not auto-rotate it
- repo-local files, committed examples, and fabric manifests must never become the only source of an actual secret value
High-Risk Interfaces
These must not be left open or unauthenticated:
/api/v1/auth/*configuration and callback-adjacent flows- Plane integration and webhook routes
- provider integration write routes
- restore, snapshot, freeze, and unfreeze routes
- approval callbacks
- runtime dispatch bridges
Webhook And Callback Contract
| Surface | Direction | Auth mechanism | Header or secret transport | Compatibility fallback | Failure code | Allowed caller class |
|---|---|---|---|---|---|---|
/api/v1/projects/{project_id}/integrations/plane/webhook | inbound | shared secret | X-Plane-Webhook-Secret | X-Webhook-Secret and ?secret= are still accepted for legacy callers; new registrations should use the dedicated Plane header | 403 when PLANE_WEBHOOK_SECRET is configured and does not match | configured Plane instance |
/api/approvals/clawledger | inbound | shared secret | X-ClawLedger-Token | none | 401 when CLAWLEDGER_APPROVAL_SHARED_SECRET is configured and does not match | configured approval system |
/api/approvals/jhf-spindle/pending | inbound | shared secret | X-ClawLedger-Token | none | 401 when CLAWLEDGER_APPROVAL_SHARED_SECRET is configured and does not match | configured approval system |
/api/approvals/clawledger/pending | inbound | shared secret | X-ClawLedger-Token | none | 401 when CLAWLEDGER_APPROVAL_SHARED_SECRET is configured and does not match | configured approval system |
/api/v1/approvals/jhf-spindle/pending | inbound | shared secret | X-ClawLedger-Token | none | 401 when CLAWLEDGER_APPROVAL_SHARED_SECRET is configured and does not match | configured approval system |
/api/v1/approvals/clawledger/pending | inbound | shared secret | X-ClawLedger-Token | none | 401 when CLAWLEDGER_APPROVAL_SHARED_SECRET is configured and does not match | configured approval system |
/api/approvals/clawledger/sync | inbound | shared secret | X-ClawLedger-Token | none | 401 when CLAWLEDGER_APPROVAL_SHARED_SECRET is configured and does not match | configured approval system |
/api/approvals/clawledger/{project_id}/{task_key}/decision | inbound | shared secret | X-ClawLedger-Token | none | 401 when CLAWLEDGER_APPROVAL_SHARED_SECRET is configured and does not match | configured approval system |
/api/approvals/clawledger/decision | inbound | shared secret | X-ClawLedger-Token | none | 401 when CLAWLEDGER_APPROVAL_SHARED_SECRET is configured and does not match | configured approval system |
OPENCLAW_RUNTIME_DISPATCH_WEBHOOK_URL | outbound | deployment-specific protected target | outside this repo | none in this repository | upstream-defined | configured runtime bridge |
N8N_OPERATOR_WEBHOOK_URL | outbound | deployment-specific protected target | outside this repo | none in this repository | upstream-defined | configured n8n operator target |
Inbound Security Rules
- inbound shared-secret checks use constant-time comparison
- missing or mismatched Plane webhook secrets are treated as
403 - missing or mismatched ClawLedger callback secrets are treated as
401 - unauthenticated compatibility fallbacks are not allowed; only the documented alternate transport keys are accepted
- new integrations should prefer explicit headers over query-string secrets
Interfaces That Must Never Be Open
- provider bootstrap/configure/revoke routes
- restore and destructive recovery actions
- runtime dispatch or control hooks
- secrets/config mutation paths
Rotation And Revocation Boundaries
- operator-managed credentials:
- provider OAuth setup saved through Settings
- workspace Plane/provider tokens saved through Settings
- revoke, replace, or re-authorize through the operator path before considering the old credential dead
- platform-managed credentials:
- database credentials
- session secret
- host-injected webhook shared secrets
- rotate outside the repository and restart or redeploy the runtime
- explicit non-goals:
- no repo-driven rotation
- no Fabric-triggered secret mutation
- no silent credential copy from standalone storage into a future integrated deployment
Automation Boundaries
The following must not be allowed as uncontrolled automation from Fabric or other external orchestrators:
- direct secret injection
- direct database mutation
- destructive project/task deletion without operator path
- restore/freeze/unfreeze without operator review
- provider auth bootstrap or revoke
- unaudited runtime dispatch
Risks
- sync drift across Gitea, Mission Control, and Plane
- provider takeover through misconfigured OAuth/bootstrap paths
- approval or webhook spoofing if secrets are weak or absent
- operator confusion if read-only discovery endpoints are mistaken for safe write surfaces
OAuth and Why It Exists Here
OAuth is relevant in this repository because Mission Control integrates with hosted/self-hosted Git providers and optional OIDC login flows.
It is not optional for those provider-backed use cases, but it is not required for every local-only development path.
OAuth Decision Rules
OAuth is required when:
- external users interact with the system
- a multi-tenant scenario exists
- access comes from outside the platform network
- a provider requires user-context authorization
OAuth is not required when:
- communication is strictly internal service-to-service
- communication is Fabric-driven and does not need user context
- a pure read-only health or discovery surface is being consumed
License: AGPLv3
Helpifyr: https://helpifyr.com