Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
6c46492
feat: converge modular SaaS platform foundations
AntoineToussaint Jul 26, 2026
411cad1
ci: pin permission-safe service agents
AntoineToussaint Jul 26, 2026
4b06380
ci: use Linux-safe Go generator
AntoineToussaint Jul 26, 2026
7e21e7f
style: gofmt/goimports fixes for accounts service
AntoineToussaint Jul 26, 2026
b98ac61
ci: separate first-party and vendor audits
AntoineToussaint Jul 26, 2026
e0cd086
fix: make raw OpenAPI a tracked Codefly output
AntoineToussaint Jul 26, 2026
288da7f
chore: align manifest with latest published tag
AntoineToussaint Jul 26, 2026
2e50dce
Merge remote-tracking branch 'https/main' into codex/converge-current…
AntoineToussaint Jul 26, 2026
33181ea
fix: converge generated OpenAPI and settings navigation
AntoineToussaint Jul 26, 2026
eea6348
Run all frontend unit tests through Vitest
AntoineToussaint Jul 26, 2026
81072ca
Pin the audited Next.js agent release
AntoineToussaint Jul 26, 2026
9e0431b
Merge branch 'main' into codex/converge-current-saas-work
AntoineToussaint Jul 26, 2026
e424259
Decouple the auth edge from Accounts implementation
AntoineToussaint Jul 26, 2026
841ac61
Merge branch 'codex/converge-current-saas-work' of https://github.com…
AntoineToussaint Jul 26, 2026
7001707
Make shared Postgres integration tests deterministic
AntoineToussaint Jul 26, 2026
d0c9ea7
Enforce Codefly SDK carriers across service languages
AntoineToussaint Jul 26, 2026
a4bd941
Adopt resilient Postgres service agent
AntoineToussaint Jul 26, 2026
652162e
Harden first-party dependency gate
AntoineToussaint Jul 27, 2026
3c45efe
Isolate nested accounts integration stack
AntoineToussaint Jul 27, 2026
3984c3a
Serialize nested Codefly integration tests
AntoineToussaint Jul 27, 2026
3cc0562
Make billing test resets atomic
AntoineToussaint Jul 27, 2026
4f6e7e6
Use kernel-isolated dependency test flows
AntoineToussaint Jul 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# protoc-gen-es emits one separator line after the final declaration.
# Keep normal whitespace checks everywhere else.
module/services/frontend/code/src/gen/** whitespace=-blank-at-eof
20 changes: 19 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ jobs:
with:
go-version: stable
cache: false
- name: Validate module agent
env:
GOWORK: "off"
run: go test ./...
- name: Reject direct Codefly runtime-carrier access
working-directory: module/tools
env:
Expand Down Expand Up @@ -60,10 +64,24 @@ jobs:
env:
CODEFLY_BASE: ${{ github.event.pull_request.base.sha || github.event.before }}
run: |
args=(ci run --head "${GITHUB_SHA}" --output .codefly/ci)
# Keep the complete audit in the Codefly evidence report, including
# vendor runtime images. Those images have their own release cadence
# and may carry upstream findings that this repository cannot patch.
# The next step separately fails closed on every first-party service
# and production frontend dependency.
# Several published vendor-image agents predate Core's shared Trivy
# cache lock. Serialize the workspace gate so those independent
# agent processes cannot corrupt or time out on the same cache.
args=(ci run --head "${GITHUB_SHA}" --output .codefly/ci --fail-on-vuln=false --jobs 1)
if [[ -n "${CODEFLY_BASE}" && "${CODEFLY_BASE}" != "0000000000000000000000000000000000000000" ]]; then
args+=(--base "${CODEFLY_BASE}")
else
args+=(--all)
fi
codefly "${args[@]}"
- name: Enforce first-party vulnerability gate
shell: bash
run: |
codefly audit service accounts --outdated=false --fail-on-vuln
codefly audit service auth-sidecar --outdated=false --fail-on-vuln
npm --prefix module/services/frontend/code audit --omit=dev --audit-level=high
7 changes: 0 additions & 7 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,6 @@ module/services/*/code/backend
module/services/*/code/local
module/services/store/code/store-migrator
module/services/*/.cache/
# Raw protoc-gen-openapiv2 output is a genuine test input for the REST-surface
# catalog (pkg/cataloggen); keep this one intermediate checked in as a fixture.
!module/services/accounts/.cache/
module/services/accounts/.cache/*
!module/services/accounts/.cache/openapi/
module/services/accounts/.cache/openapi/*
!module/services/accounts/.cache/openapi/api.swagger.json

# nix caches + materialized per-service nix envs (machine-local, regenerated)
**/.nix-cache/
Expand Down
19 changes: 10 additions & 9 deletions DOGFOODING.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,21 @@ current source.
# 1. Build agents (s3 plugin v0.0.2 must be installed locally)
cd ~/Development/deus/codefly.dev/agents/services/s3 && codefly agent build

# 2. Sync the module so codefly picks up the new object-storage entry
cd ~/Development/deus/codefly.dev/agents/modules/saas-starter
codefly sync service # for each: api, frontend, object-storage
# 2. Enter the standalone starter repository
cd ~/Development/deus/codefly/module-saas-starter

# 3. Boot the stack
codefly run service frontend --fixture dev-admin
codefly run service --fixture dev-admin
```

Expected boot order: `vault → store → cache → object-storage (s3 plugin
→ MinIO at port 9xxx) → api → auth-sidecar → frontend`. If any service
Expected graph: `vault + store + cache + object-storage (s3 plugin
→ MinIO at port 9xxx) → accounts → frontend → auth-sidecar`. Independent
services may start concurrently. If any service
hangs at "waiting for ready", check that step's `--debug` output.

The TUI shows green dots when each service is up. Wait for **frontend**
to report a URL — typically `http://localhost:21931`.
The TUI shows green dots when each service is up. Wait for **auth-sidecar**
to report its public HTTP URL. Open that URL; the frontend's direct URL bypasses
authentication routing and is not the application ingress.

---

Expand Down Expand Up @@ -168,7 +169,7 @@ service. Use a Stripe test-mode key.

```bash
codefly secret set api STRIPE_API_KEY sk_test_xxxxxxxxxxxx
codefly run service frontend --fixture dev-admin
codefly run service --fixture dev-admin
```

- [ ] `/admin/billing` — Plan card shows **Pro** badge.
Expand Down
75 changes: 66 additions & 9 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

Status: active
Started: 2026-07-12
Last reviewed: 2026-07-26
Companion checklist: [TODO.md](TODO.md)

This roadmap turns the architecture review into an executable program of work.
Expand Down Expand Up @@ -353,6 +354,16 @@ SBOM attestations for exact image digests on main and release tags. Runtime
images use pinned current bases, non-root users, and no package managers; the
database migration image is a minimal Postgres-only binary instead of the
vulnerability-heavy all-driver upstream CLI.
The frontend now uses Next.js 16.2.11 and React/React DOM 19.2.8 with the stable
React Compiler.
App Router page and layout files remain server boundaries, while authentication,
plugin routing, accordions, and browser-origin discovery live in narrow client
islands. A script-free external-store theme provider replaces `next-themes`, and
compiler correctness findings are enforced. The same baseline is implemented in
the Codefly Next.js factory; Codefly's shared Node upgrader now understands npm
11 workspace arrays, upgrades peer-coupled packages atomically per workspace,
and reports workspace-only changes. Publishing core and agent 0.0.115 remains a
separate release step before consumer pins move.
The CI workflow now exposes an aggregate clean-checkout check that cannot pass
when a prerequisite is skipped, runs version tags, and promotes only after the
complete Playwright suite succeeds against a freshly created Codefly `dev-admin`
Expand Down Expand Up @@ -412,7 +423,7 @@ protobuf. Complex state-dependent authorization stays in domain code.
Implemented: `saas.policy.v1.MethodPolicy` defines finite exposure,
tenant, permission/scope, resource-binding, MFA, audit, idempotency, rate-limit,
platform-role, and sensitivity vocabulary as extension `51000` of
`MethodOptions`. All 114 RPCs are annotated. Exact local Codefly generation
`MethodOptions`. All 125 RPCs are annotated. Exact local Codefly generation
emits Go and TypeScript bindings; runtime admission and the review matrix read
the descriptors directly; validation rejects incomplete policy, bad vocabulary,
and invalid resource field paths. `module/METHOD_POLICY.md` defines the
Expand All @@ -436,35 +447,35 @@ has functional equivalence and migration tests.

Implemented foundation: `saas.catalog.v1` supplies generated Go and TypeScript
catalog types, and the accounts compiler discovers every service directly from
the registered protobuf file graph. It emits a deterministic 23-service,
114-method `generated/service-catalog.json` with canonical procedures,
the registered protobuf file graph. It emits a deterministic 25-service,
125-method `generated/service-catalog.json` with canonical procedures,
request/response and streaming shape, all HTTP bindings, full typed policy,
source provenance, and Codefly ownership. Semantic validation and CI fail on
missing/invalid policy, duplicate routes, incomplete ownership, inventory
ordering/grouping drift, unknown permission/scope vocabulary, invalid
entitlement definitions, transport mismatch, or generated-file drift. The
catalog plus a strict finite implementation-binding file now generates every
Connect registration and compile-time handler-interface assertion. Runtime mux
parity proves all 114 catalog procedures resolve through 23 Connect service
parity proves all 125 catalog procedures resolve through 25 Connect service
patterns; the former handwritten registration block is gone. The gateway
compiler emits a typed 325-route public-edge inventory, generated
compiler emits a typed 355-route public-edge inventory, generated
auth-sidecar/Envoy Connect whitelist, and exact/path-template Istio manifest
with Codefly ownership and named endpoints. Internal methods are omitted and
public/protected behavior is descriptor-derived. Istio activation waits for the
frontend/static route catalog so deployment cannot regress to an API-only
surface. The authorization compiler now emits `saas.authz.methods.v1` for all
114 procedures with complete policy, deterministic policy fingerprints, and
125 procedures with complete policy, deterministic policy fingerprints, and
edge limiter behavior. Auth-sidecar joins Connect and known REST routes to its
generated policy lookup; parity repaired stale registration exposure and URL
classification is gone from limiter failure handling. The generated
`saas.rest.surface.v1` projection now drives 109 opt-in descriptor routes,
`saas.rest.surface.v1` projection now drives 119 opt-in descriptor routes,
accounts registration/allowlisting, auth-sidecar routing, and verified public
OpenAPI; internal RPCs have no HTTP annotations and five non-protobuf routes
remain explicit extensions. The frontend projection now generates typed
Connect clients for all 23 accounts services plus finite permission, API-key
Connect clients for all 25 accounts services plus finite permission, API-key
scope, and entitlement constants. Frontend role gates, common client hooks,
and entitlement administration consume those types, while Go and Vitest parity
tests pin all 114 procedures. The deployment projection now compiles a strict
tests pin all 125 procedures. The deployment projection now compiles a strict
module topology into the actual Codefly module/service manifests, a typed
7-service/11-endpoint/8-dependency inventory, and 15 default-deny Kubernetes
NetworkPolicies. Each service edge is limited to declared endpoint ports;
Expand Down Expand Up @@ -494,6 +505,12 @@ two module-interface exports, and finite public egress. Generation writes the
runtime `module.codefly.yaml`/`service.codefly.yaml` files and removes the broad
intra-namespace allow policy in favor of dependency-specific ingress/egress.
DNS, Istio control-plane/ingress, and HTTPS egress remain explicit exceptions.
The same source declares `auth-sidecar` as the module service entry. Because the
sidecar depends on the frontend, accounts, and cache—and those dependencies pull
in the remaining infrastructure—Codefly resolves the complete seven-service
graph from either the module directory or the repository's single-module
workspace without a manually repeated service name. Its public HTTP endpoint is
the application ingress; the frontend remains private behind it.

Reference: <https://connectrpc.com/docs/go/getting-started/> and
<https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/ext_authz_filter>.
Expand Down Expand Up @@ -572,6 +589,46 @@ privacy/billing workflows are recoverable.
types.
- Support seats and usage as separate meters with reconciliation jobs.

### P2.6 Principal authority and Work Context

- Treat every direct RBAC subject as a Principal, not as a human user. Teams
remain indirect/group subjects. Preserve the legacy `SUBJECT_KIND_USER = 1`
protobuf alias for compatibility while making `SUBJECT_KIND_PRINCIPAL = 1`
canonical and migrating stored `user` assignments to `principal`.
- Issue short-lived, audience-bound Codefly Work Context capabilities from the
permissions plugin for a new Task/root Session, another root Session under
the same Task, or an attenuated child-agent Session.
- Resolve owner membership, active Agent Principal, exact requested
resource/action/scope grants, team attribution, and monotonic organization /
Principal authorization revisions inside one verified `service-postgres`
Reader transaction. A request field or cached display context may not select
the authoritative tenant or Principal.
- Keep Task and Session lifecycle rows in the product. Accounts owns current
identity/RBAC and capability exchange only.
- Cache permission computations only behind revisioned keys and explicit
invalidation. Issuance and row-level authority must fail closed when current
revision state cannot be established; stale cache may narrow presentation but
never widen execution or reads.

Implemented foundation: `WorkContextService` contributes three generated
gRPC/Connect/REST operations and uses the shared Codefly Ed25519 Work Context
SDK. Migrations 78–79 add authorization revisions and principal-uniform role
subjects. The store binds verified tenant/owner scope, checks exact owner and
Actor authority, and signs only current facts. Compile, RPC attenuation, direct
Agent Principal, human RBAC, cross-tenant RLS, database-role, grant, inventory,
and policy tests pass against fresh Codefly-managed PostgreSQL.

Acceptance criteria:

- One human owner can authorize a registered Agent Principal without encoding
the Agent as a user.
- A child Session can only attenuate its parent capability and cannot change
Task owner or tenant.
- Revoked membership, revoked Actor, changed role/scope, stale revision, foreign
tenant, wrong audience, expiry, and replay-policy violations fail closed.
- A real product consumes the capability through released Codefly/Warden SDKs
without importing Accounts internals or scanning Codefly carriers.

## Phase 3: plugin platform and Mind delegation

Exit gate: compile-time plugins are the default extension mechanism, Warden can
Expand Down
Loading
Loading