Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .autodev/state/phase-progress.jsonl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"ts":"2026-05-27T07:31:06Z","ev":"plan","pl":"2026-05-27-auth-admin-contracts.md","st":"complete","e":"Auth PR #36 and scenario PR #28 green in GitHub checks; no unresolved non-outdated review threads; auth release v0.2.9 green; scenario Docker app healthy; local and tailnet /admin redirect to login; scenario tests 89 passed, 0 failed; Playwright screenshots generated."}
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,23 @@
- README verified-status banner per workflow#714 (multi-repo QoL sweep).
- CONTRIBUTING.md, examples/minimal/config.yaml, and GitHub issue/PR templates.

## v0.2.9 (2026-05-27)

### Added

- Added strict proto admin config contracts:
- `step.auth_admin_config_describe`
- `step.auth_admin_config_validate`
- Admin descriptors expose grouped controls, labels, help text, input types,
config keys, disabled reasons, and write-only secret configured state.
- Admin validation rejects unsafe auth config patches, including production
password enablement and zero-primary-method configs when required.

### Security

- Admin describe/validate outputs never echo secret values; outputs return
sanitized config plus `secret_fields` metadata.

## v0.2.4 (2026-05-13)

### Strict-proto config-field gaps closed (BMW local smoke vs workflow v0.51.5, round 3)
Expand Down
23 changes: 21 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ The plugin binary itself is distributed via public GitHub Releases — `GH_TOKEN
- `step.auth_policy_gate`
- `step.auth_methods_response`
- `step.auth_policy_audit`
- `step.auth_admin_config_describe`
- `step.auth_admin_config_validate`
- `step.auth_oauth_provider_config`
- `step.auth_oauth_start`
- `step.auth_oauth_exchange`
Expand Down Expand Up @@ -93,10 +95,27 @@ issuance in the consuming app.
shape. `step.auth_policy_audit` reports production password policy violations
for CI or operational checks.

## Admin Configuration Contracts

`step.auth_admin_config_describe` exposes a strict proto contract for admin
portals to render authentication settings. It returns grouped controls with
labels, help text, input types, config keys, disabled reasons, and write-only
secret state. Controls map to real plugin config keys consumed by the auth
policy, OAuth, WebAuthn, challenge, and delivery steps.

`step.auth_admin_config_validate` accepts a desired config patch and returns a
sanitized accepted patch plus diagnostics. The plugin validates the patch; the
admin host persists accepted config into Workflow configuration or its own
config store. Secret values are never echoed in outputs. Production password
auth, incomplete passkey settings, incomplete OAuth settings, and zero-primary
method configurations are rejected when applicable.

## OAuth

The first OAuth slice supports Google. Other providers currently return disabled
metadata and are not advertised as login-ready.
OAuth provider config supports Google and Facebook. Policy advertising remains
conservative and only marks providers login-ready when the configured provider
is supported by the current policy path. Instagram, X, and unknown providers
return disabled metadata and are not advertised as login-ready.

`step.auth_oauth_start` emits `state`, optional PKCE values, `return_to`,
`expires_at`, and `authorization_url`. The plugin does not store OAuth state.
Expand Down
6 changes: 6 additions & 0 deletions SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ Policy:
- `step.auth_methods_response` — frame methods in API response
- `step.auth_policy_gate` — pre-handler gate
- `step.auth_policy_audit` — audit trail
- `step.auth_admin_config_describe` — admin-renderable auth config controls
- `step.auth_admin_config_validate` — validate and sanitize admin config patches

Misc:
- `step.auth_normalize_phone`
Expand All @@ -103,6 +105,9 @@ Misc:
- V5: WebAuthn RP ID + origin pinned to env vars (no silent cross-origin).
- V6: Disable_password_auth=true at module config → password steps return `{"disabled": true}` + endpoints return 410.
- V7: Module-level disable knob, not global — multiple credentialModule instances may differ.
- V8: Admin config describe/validate outputs MUST NOT echo secret values; outputs expose configured state and `secret_fields` only.
- V9: Admin config validation MUST reject production password enablement and zero-primary-method configs when `require_primary_method` is true.
- V10: Admin config controls MUST map to real plugin config keys; no UI-only fake auth toggles.

## §T — Tasks (status as of 2026-05-25)

Expand All @@ -119,6 +124,7 @@ Misc:
| T-AUTH-9 test matrix | ⚠️ partial | 16 test files |
| T-AUTH-10 SPEC.md backport | ✅ (this doc) | filed as #33 |
| T-AUTH-11 registry manifest update | ✅ | workflow-registry#149 merged |
| T-AUTH-12 admin config contracts | ✅ | `step.auth_admin_config_describe`, `step.auth_admin_config_validate`, strict proto contracts |

## §X — References

Expand Down
130 changes: 130 additions & 0 deletions docs/plans/2026-05-27-auth-admin-contracts-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# Auth Admin Contracts Design

## Goal
Add real workflow-plugin-auth administrative contracts so admin portals can discover, render, validate, and persist auth configuration through Workflow-owned config, not demo-only UI state.

## User Requirements
| id | requirement | design response |
|---|---|---|
| R1 | Admin portal configures real auth plugin behavior | Add strict proto admin describe/validate steps over existing auth config keys. |
| R2 | Passkeys, password disable, OAuth, and other auth modes must be administrable | Descriptor groups expose passkey, password, email code, SMS code, TOTP, Google OAuth, Facebook OAuth controls. |
| R3 | Toggles wired to real plugin config, always | Control `config_key` values map to keys already consumed by `auth_methods_policy`, OAuth, credential module, and send/challenge steps. |
| R4 | Plugin-first; demo is proof only | Scenario consumes contract-shaped API data and applies returned config patches; no scenario-only auth semantics. |
| R5 | Security standard | Secrets redacted, validation fail-closed, production password restrictions preserved, unsafe OAuth endpoints rejected unless explicitly configured for tests. |
| R6 | Releases generated after tested/proven | Bump plugin manifest to next version, validate contract, tag release after verification. |

## Global Design Guidance
Source: workspace `AGENTS.md`, `SPEC.md`, `README.md`.

| guidance | response |
|---|---|
| Prefer Workflow/plugin ownership boundaries | Auth plugin owns auth contracts and validation; admin/dashboard owns rendering and persistence orchestration. |
| Avoid stubs/TODO-only/partial wires | New admin controls bind to existing executable config keys; unsupported modes are marked unavailable rather than shown as functional. |
| Strict proto contracts | New admin steps have generated protobuf messages, runtime registry descriptors, and `plugin.contracts.json` entries. |
| Security/quality first | Secret redaction tests, unsafe-change tests, production password gating, and no secret echo in describe/validate outputs. |
| Scenario proves platform capability | `workflow-scenarios` gets light UI/API updates that consume the contract-shaped surface and preserve authz enforcement paths. |

## Approaches Considered
| option | summary | trade-off | decision |
|---|---|---|---|
| A | Admin-specific step contracts in auth plugin | Fits existing strict step registry and Workflow DSL; host persists config patch. | Chosen. Minimal new host assumptions; real plugin contract. |
| B | New long-running auth admin service | More direct CRUD semantics; heavier lifecycle/discovery surface than current plugin precedent. | Rejected for now; no existing service pattern in this repo. |
| C | Keep admin UI-owned JSON schema | Fast UI iteration; duplicates plugin truth and can drift. | Rejected; violates plugin-first/no-fake requirement. |

## Architecture
| component | responsibility |
|---|---|
| `step.auth_admin_config_describe` | Merge plugin config + runtime config + input, return sanitized effective settings, capabilities, control groups, warnings. |
| `step.auth_admin_config_validate` | Accept desired config patch, reject unsafe/incomplete changes, return sanitized accepted patch + effective policy + diagnostics. |
| `AuthAdmin*` proto messages | Stable contract for admin renderers: groups, controls, option lists, diagnostics, secret config state, OAuth provider state. |
| Existing `auth_methods_policy` helpers | Source of truth for which methods are actually enabled. Admin contracts call the same policy path. |
| Scenario admin UI | Renders tabs and labeled controls from contract-shaped JSON; submits patches through scenario API that applies plugin-equivalent validation. |

## Contract Shape
| message | key fields |
|---|---|
| `AuthAdminConfig` | `environment`, passkey keys, email/SMS keys, password toggles, TOTP toggles, OAuth provider client/redirect keys, secret fields. |
| `AuthAdminDescribeInput` | Optional desired environment/context override; no secrets required. |
| `AuthAdminDescribeOutput` | `groups`, `effective_config`, `methods_policy`, `warnings`, `secret_fields`, `error`. |
| `AuthAdminValidateInput` | `desired_config`, `require_primary_method`, optional `allow_secret_placeholders`. |
| `AuthAdminValidateOutput` | `valid`, `accepted_config`, `methods_policy`, `errors`, `warnings`, `secret_fields`, `error`. |
| `AuthAdminControl` | `key`, `label`, `description`, `help_text`, `input_type`, `config_key`, `secret`, `configured`, `required`, `enabled`, `disabled_reason`, `options`. |

Admin update persistence is intentionally not inside workflow-plugin-auth: the plugin validates and returns a config patch. The host/admin plugin writes that patch into Workflow config or its chosen config store. This avoids fake persistence and keeps declarative Workflow config as source of truth.

## Security Review
| risk | mitigation |
|---|---|
| Secret disclosure through admin describe/validate | Secret values are never returned; outputs expose `configured=true/false` and `secret_fields`. |
| Admin enables zero primary login methods | Validation rejects when `require_primary_method=true` and policy result has `primary_method_count=0`. |
| Password auth in production | Existing production block stays authoritative; admin validate returns error/warning instead of enabling passwords. |
| OAuth SSRF / malicious endpoints | Existing OAuth endpoint validation preserved; insecure test endpoints require `allow_insecure_test_oauth_endpoints=true`. |
| Confused UI labels cause unsafe changes | Controls carry labels, descriptions, help text, disabled reasons, and group context. |
| Demo bypasses auth/authz semantics | Scenario admin endpoint remains behind login/session and admin scope; UI only proves contract consumption. |

## Infrastructure Impact
| area | impact |
|---|---|
| Cloud resources | None. |
| Secrets | Existing auth secrets may be configured through host; plugin only validates presence/redacts values. |
| Network | No new network listeners; release workflow/tag push after verification. |
| Plugin loading | New step types require manifest/contract update; validate with `wfctl plugin validate-contract --for-publish`. |
| Runtime | Existing apps can ignore new step types; backward-compatible additive contract. |

## Multi-Component Validation
| boundary | proof |
|---|---|
| Plugin proto ↔ runtime registry ↔ manifest | `GOWORK=off go test ./...`, contract registry test, `wfctl plugin validate-contract --for-publish --tag v0.2.9 .`. |
| Admin contract ↔ auth policy | Unit tests assert describe/validate mirrors `auth_methods_policy` for passkey/password/OAuth/TOTP/SMS/email. |
| Plugin contract ↔ scenario UI | Scenario API returns contract-shaped payload; Playwright exploratory QA verifies controls render/select/update and auth gate still blocks anonymous admin. |
| Release | Manifest version bumped, local checks pass, tag pushed to trigger release workflow. |

## Assumptions
| id | assumption | challenge | fallback |
|---|---|---|---|
| A1 | Admin plugin/host can persist accepted config patches | Host persistence may not exist yet | Contract returns patch and diagnostics only; scenario uses in-memory/demo persistence as consumer proof, not plugin persistence. |
| A2 | Step contracts are the right current extension point | Future Workflow may prefer service contracts | Additive step types can coexist; service wrapper can call same helpers later. |
| A3 | Google/Facebook are the only real OAuth providers currently implemented | Proto has Instagram/X secret fields but runtime says disabled | Descriptor marks unsupported providers unavailable until real runtime support exists. |
| A4 | Password support remains allowed outside production | Some apps may forbid passwords everywhere | Admin config can set `password_auth_enabled=false`; future host policy can impose stricter constraints via input. |

## Self-Challenge
| doubt | answer |
|---|---|
| Could this be just JSON schema in the admin UI? | That would drift from plugin behavior and violates plugin-first requirement. |
| Does validate imply persistence? | No; output is an accepted patch. Persistence belongs to Workflow config/admin host. |
| Is this too broad? | Scope stays to existing auth modes; no new auth providers or credential stores are added. |

## Rollback
| change | rollback |
|---|---|
| Plugin code/contracts | Revert feature commits; old step types remain unchanged. |
| Manifest/version bump | Revert manifest/contract changes or publish a follow-up tag pointing at rollback commit. |
| Scenario UI/API proof | Revert scenario commits; plugin contract remains independently usable. |
| Release tag | If tag is pushed and bad, publish next patch tag with rollback/fix; do not delete public release tags. |

## Adversarial Design Review
### Report
**Phase:** design
**Artifact:** `docs/plans/2026-05-27-auth-admin-contracts-design.md`
**Status:** PASS

| sev | class | loc | issue | fix |
|---|---|---|---|---|
| Minor | Simpler alternative | Approach C | UI-only schema is simpler but rejected due user requirement. | Keep rejection explicit. |
| Minor | Infrastructure | Release | Tag push has external release effect. | Gate tag on local contract/test proof and use next patch tag rollback. |
| Minor | Multi-component validation | Scenario | Scenario cannot prove actual host persistence. | Limit claim to contract consumption; plugin validates patch, host persistence out of contract. |

### Bug-Class Scan
| class | result | note |
|---|---|---|
| Project-guidance conflicts | Clean | Plugin-first ownership follows workspace and repo guidance. |
| Assumptions under attack | Clean | Persistence and provider support assumptions listed with fallback. |
| Repo-precedent conflicts | Clean | New surface uses existing strict step contract pattern. |
| YAGNI | Clean | No new auth provider/runtime store introduced. |
| Missing failure modes | Clean | Secret redaction, zero-primary, production password, OAuth endpoint abuse covered. |
| Security/privacy | Clean | No secret echo; fail-closed validation. |
| Infrastructure impact | Clean | Release/tag impact stated; no infra resource changes. |
| Multi-component validation | Clean | Plugin registry/manifest and scenario UI proof included. |
| Rollback | Clean | Runtime/release rollback path stated. |
| User-intent drift | Clean | Directly targets real plugin contracts and scenario proof. |

Loading
Loading