Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
bc90fdb
chore(gen): ReadJournal contract, waiting for the saas-starter release
crisfiorini-oss Oct 12, 2026
c91ffdd
feat(moduleauthority): ReadJournal reads the host's journal forward
crisfiorini-oss Oct 12, 2026
2f99945
feat(moduleauthority): ReadJournal reads by page with opaque positions
crisfiorini-oss Oct 13, 2026
381afff
feat(moduleauthority): export JournalStart, the position before the o…
crisfiorini-oss Oct 13, 2026
fd1472d
fix(sdk): reproduce journal API from the exact host contract
crisfiorini-oss Oct 13, 2026
413ed1f
test(moduleauthority): use sealed journal credential fixtures
crisfiorini-oss Oct 13, 2026
c11c47f
fix(sdk): reconcile journal schema and workload gateway conformance
crisfiorini-oss Oct 15, 2026
bdb8717
chore: mark generated SDK bindings for review
crisfiorini-oss Oct 21, 2026
10b87f2
fix(sdk): regenerate journal API against current host authority
crisfiorini-oss Oct 21, 2026
4a785ff
docs(sdk): align journal provenance with rebased host source
crisfiorini-oss Oct 21, 2026
1fcb2fc
fix(journal): align host provenance and use released Core
crisfiorini-oss Oct 23, 2026
5096931
fix(sdk): refresh journal contract and reuse shared approval types
crisfiorini-oss Oct 26, 2026
25eddbd
feat(sdk): reuse journal transport with shared Authority capabilities
crisfiorini-oss Oct 27, 2026
e73eff1
chore(sdk): regenerate the rebased host journal contract
crisfiorini-oss Oct 27, 2026
140f69e
chore(sdk): track shared installation-compatible host source
crisfiorini-oss Oct 27, 2026
ccb34ed
docs(sdk): require a qualified journal credential producer
crisfiorini-oss Oct 27, 2026
4bbea05
refactor(sdk): reuse the existing journal client
crisfiorini-oss Oct 27, 2026
f73008b
ci(sdk): qualify source branch pushes through the existing gates
crisfiorini-oss Oct 27, 2026
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
3 changes: 2 additions & 1 deletion .claude/skills/refresh-generated-api/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ Three properties of that template matter:
version that provides those packages; validate the dependency floor against
SDK and consumer builds instead of copying the host's dependency generation.
Generating another copy of Core's descriptors here creates duplicate protobuf
registrations at initialization.
registrations at initialization. Shared `host/` installation imports likewise
resolve to the canonical Authority client rather than another descriptor copy.

- **`clean: true` wipes `gen/` first.** So a proto deleted upstream disappears
here rather than lingering — which is how `AuditExportService` left in 0.1.0.
Expand Down
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Host-owned protocol bindings are generated. Keep facades and locks visible.
gen/** linguist-generated=true
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ name: ci

on:
push:
branches: [main]
pull_request:
workflow_dispatch:

permissions:
contents: read
Expand Down
3 changes: 2 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ examples. Read it rather than re-deriving the API from the tree.
file descriptors embed length-prefixed package strings; a text rewrite
corrupts them and panics at `init()`. Regenerate (skill below).
Generate the host-owned `saas/` tree; Core's vendored Runnable imports resolve
to Core's Go dependency, never a second descriptor copy in this SDK.
to Core's Go dependency; `host/` installation imports resolve to the canonical
Authority client. Neither shared descriptor tree is copied into this SDK.
- **Every generated type reachable from a facade needs an alias in that
package's `types.go`** — and a generated enum needs its constants
re-exported too, because an alias carries the type and not the constants.
Expand Down
82 changes: 68 additions & 14 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,38 @@

## Unreleased

Core main and module-saas-starter v0.0.103. No Core tag carries the Core this
needs, so the floor is a pseudo-version; it moves to the first tag that does.
The journal contract uses the exact module-saas-starter development source in
`SOURCE.txt`. Shared installation approval types come from the canonical
Authority client; its declared Core dependency sets the development floor.

### Changed

- **Core floor: `v0.19.6-0.20261018051341-b81d92e6feda`** (Core main,
2026-10-18), from v0.19.4 on this branch and v0.19.1 in v0.1.3. Core
`22ddde98` removed the approved build from a Work Context: `SealSource` lost
`ApprovedBuild` and `ErrNoApprovedBuild` is gone, so v0.1.3 does not compile
for any consumer that requires that Core. It is also the Core the v0.0.103
gateway requires. Core v0.19.5 still requires `SealSource.ApprovedBuild` and
cannot build this release; MVS never selects it beside this floor.
- **`gen/` moves from `9ab36e7e` to released module-saas-starter v0.0.103**
(`2cb00737`), with the existing plugin pins and buf v1.73.0. The tree
reproduces byte-for-byte from that tag, and `SOURCE.txt` records it for both
`gen-drift` and `conformance/hostgateway`. The module package version stays
0.1.0; regeneration cuts no SDK release.
- Reuse the host protobuf request constraints in `Client.ReadJournal` before
obtaining credentials; reject invalid supplied timestamps. Keep the existing
broker, module-credential cache, refresh-once behavior and Accounts transport.
No second reader factory or credential-producer API is added. Generic shared
Authority Issue does not mint the required unbound module identity; consuming
modules must qualify their producer route separately.

- Refresh development provenance to the rebased module-saas-starter journal
source recorded in `SOURCE.txt`, with module package version 0.2.0. The full
generated API carries the latest host fields, including installation approval
and workload operation admission. No SDK release is published.

- **Shared installation approval bindings** resolve to the existing Authority
client at `v0.0.0-20261026143932-67b85b14a942`, rather than generating a second
`host.*` descriptor tree. That client requires Core
`v0.19.7-0.20261026092055-b23dc13543b2`, the SDK's development floor. Core
`v0.19.6` supplies the earlier Work Context APIs but does not satisfy the
canonical client's declared floor. These are development source pins;
publication remains gated on actual compatible owner releases. Go 1.27.3
remains the minimum toolchain.
- **`gen/` adds the journal and delivery contract to the current host schema.**
The complete host-owned `saas/` tree is generated from the exact development
source recorded in `SOURCE.txt`, with buf 1.73.0 and the existing plugin pins.
The generated tree retains current main's solution registry and datasource
contracts. Regeneration cuts no SDK release; publishing follows the host
release and replacement of the development source with its release tag.
- **The module broker is the gateway's workload endpoint.** Host `af5cef9a`
(module-saas-starter#1120) serves the three mints there alone — the public
endpoint answers 404 — and `Seams.Gateway`'s documentation now says so. The
Expand All @@ -33,6 +48,13 @@ needs, so the floor is a pseudo-version; it moves to the first tag that does.

### Removed (breaking)

- The journal generation adds methods to generated interfaces:
`AuditServiceClient`/`Handler.DeliverAuditEvents` and
`.LookupDeliverAuditEvents`, `ModuleCapabilitiesServiceClient`/`Handler.ReadJournal`,
and `WorkContextServiceClient`/`Handler.AdmitWorkloadOperation`.
Implementers must provide the methods or embed the generated
`Unimplemented…Handler`. No existing generated symbol is removed relative
to current main.
- **`(*moduleauthority.WorkContextSources).ApprovedBuild`**. Core's verifier
no longer asks an issuer for an approved build — a change of approved builds
revokes through the principal's epoch and the installation's revision — and
Expand All @@ -56,6 +78,38 @@ needs, so the floor is a pseudo-version; it moves to the first tag that does.

### Added

- The refreshed host schema includes installation revision and explicit
`InstallSolutionRequest.Approval` (`ConsentApproval` from Authority), workload
operation admission, task operation bindings, declaration-digest checks,
viewer Work Context fields and service interface-package inventory. These
are the host's contracts; the SDK adds no alternate admission or approval path.

- `Client.ReadJournal(ctx, after, limit, types, deliveryBindings) (JournalPage, error)`
calls `ModuleCapabilitiesService.ReadJournal` on the authority endpoint as the
module, through the same credentials and refresh-once rule as every authority
call. The host serves it only to a cross-tenant module principal; any other
caller gets the host's `PermissionDenied`, preserved. Positions are opaque
strings: `after` is exclusive, `""` reads from the oldest retained entry, and
`JournalPage.NextAfter` is the resume point the host guarantees misses no
committed entry and never passes an unfinished transaction, so a reader
resumes from it rather than from the last `Position` it saw, and only stores
and compares positions for equality.
- `JournalStart` (`"start"`) is the position that means "before the oldest
retained entry": the host accepts it as `after`, and as the `from` of its
delivery operation, and never returns it as an entry's position. A reader with
no position of its own starts from it.
- `deliveryBindings` are the caller's binding ids whose mints and exchanges count
as delivery machinery; the host sets `JournalEntry.DeliveryMachinery` on the
entries that record one of them, or the caller's own module work-context mint,
so a reader that delivers journal entries can tell a page of its own delivery
from a page of real activity. A limit outside 0..500 (0 is the host's default of
100), no type, or an empty type or binding id is `ErrInvalidJournalRead` before
any call.
- Generated: `ReadJournal` on `ModuleCapabilitiesService`, with
`ModuleReadJournalRequest`, `ModuleJournalEntry` and
`ModuleReadJournalResponse`; `DeliverAuditEventsResponse.From` and `To`
carry the exact committed receipt interval for retention coverage checks.

- **`accounts.Client.Datasources()`**, the `DatasourceService` facade beside
`Audit()`: `ListSources`, `GetSource`, `AddSource`, `ListSourceOperations`,
`DeclareSourceOperations`, `InvokeSourceOperation`,
Expand Down
39 changes: 28 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -305,8 +305,8 @@ The SDK surfaces are:
It talks to the two seams the host serves a composed module, and takes both
explicitly — the consumer passes what Codefly resolved, nothing is defaulted:

- the **gateway's module broker** (REST on the auth-gateway's `rest`
endpoint): `POST /modules/_work-context`, `/modules/_operation-context`
- the **gateway's module broker** (HTTP on the auth-gateway's `workload`
endpoint, API `http`): `POST /modules/_work-context`, `/modules/_operation-context`
and `/modules/_source-operation-context`, where the module presents its
pod's projected ServiceAccount token (audience `accounts`) as the bearer;
the host reviews it and mints only for the principal's declared workload
Expand All @@ -318,7 +318,7 @@ The SDK surfaces are:

```go
authority, err := moduleauthority.New(moduleauthority.Seams{
Gateway: gw, // BaseURL() + HTTPClient()
Gateway: workloadGateway, // resolved workload endpoint + HTTPClient()
Authority: moduleauthority.Authority{Address: authorityHostPort}, // TLS: nil = h2c
InternalToken: internalToken,
// Only from the consumer's own configured assertion that every
Expand Down Expand Up @@ -526,14 +526,15 @@ The template generates the complete host-owned `saas/` schema tree. Its
vendored `codefly/` import closure is compiled for Runnable annotations, with
imports resolved to `github.com/codefly-dev/core/generated/go`; Core owns
those Go descriptors. Emitting a second copy in this SDK would conflict at
protobuf initialization. The SDK requires Core at `b81d92e6feda`
(`v0.19.6-0.20261018051341-b81d92e6feda`), the Core the v0.0.103 gateway
requires: it supplies the Runnable package, and its `SealSource` has no
approved build. No tagged Core carries that yet; v0.19.5 still requires
`SealSource.ApprovedBuild`, so it cannot build this SDK, and the floor moves to
the first Core tag that contains `b81d92e6feda`. The SDK need not adopt the
host's entire dependency generation. Verify the compatible dependency floor
with SDK and consumer builds when refreshing it.
protobuf initialization. The `host/` installation import similarly resolves to
`github.com/codefly-dev/authority/libraries/authority-client/go/gen`, the
existing owner of shared `ConsentApproval` bindings. The canonical Authority
client at `v0.0.0-20261026143932-67b85b14a942` requires Core
`v0.19.7-0.20261026092055-b23dc13543b2`; these development source pins are not
published release tags. Publishing the SDK requires compatible owner releases.
The dependency requires Go 1.27.3. Core v0.19.5 still requires
`SealSource.ApprovedBuild`, so it cannot build this SDK. Verify the compatible
dependency floor with SDK and consumer builds when refreshing it.
The generation plugin versions remain pinned.
Record the release tag in `SOURCE.txt`; CI checks out that tag through
`refs/tags/` and verifies that regeneration leaves no diff. Before a host
Expand Down Expand Up @@ -743,3 +744,19 @@ their context's `Err()` for cancellation. For example, a caller may retry a 502,
denial. The SDK does not automatically retry broker failures. Malformed initial
HTTP headers provide no usable status and produce a transport error; malformed bodies cannot
change a successfully parsed non-200 status into a transport failure.

### Journal client reuse

`moduleauthority.Client.ReadJournal` reuses this client's broker, module-credential
cache and refresh-once behavior, existing Accounts HTTP/2 transport, and journal
projection. The host protobuf constraints validate requests before credentials
are obtained. Invalid nonempty timestamps are refused before a page is returned.
No additional reader factory or credential-producer API is added.

Generic shared Authority `Issue` requires an operation binding and cannot mint
an unbound `module-capabilities` identity. A consumer must qualify its credential
route; transport tests alone do not establish producer compatibility.

| Build or reuse | Searched and verified | Result |
| --- | --- | --- |
| Journal client | Existing Client module credentials, cache, callAsModule transport, protobuf request constraints and journal tests | Extend Client.ReadJournal. Remove the unqualified second reader factory; reuse the existing broker, cache and decoder instead of adding a credential API. |
12 changes: 5 additions & 7 deletions SOURCE.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
gen/ generated from codefly-dev/module-saas-starter@v0.0.103
gen/ generated from codefly-dev/module-saas-starter@bb66a84cfff053bcccf3f0842bc6ffa6b2e0d159
(accounts public proto: module/services/accounts/proto)
(auth gateway: module/services/auth-gateway/code)

module version: 0.1.0 (module/module.package.codefly.yaml)
This SDK's release is matched to the saas-starter module version above.

Released upstream tag: v0.0.103 (2cb00737ed56c79c823bc82f4055681a51919e7c).
Its auth gateway requires codefly-dev/core at b81d92e6feda, the floor this
SDK's go.mod records.
module version: 0.2.0 (module/module.package.codefly.yaml)
Development source: exact PR-head commit of module-saas-starter#1106.
The entire host-owned saas/ tree is generated with this repository's buf.gen.yaml.
Replace this development ref with the host release tag before publishing the SDK.
Regeneration does not publish an SDK release.
5 changes: 5 additions & 0 deletions buf.gen.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ managed:
- file_option: go_package_prefix
path: codefly
value: github.com/codefly-dev/core/generated/go
# Shared installation approvals belong to the canonical Authority schema.
# Import those bindings rather than registering another host.* descriptor.
- file_option: go_package_prefix
path: host
value: github.com/codefly-dev/authority/libraries/authority-client/go/gen
plugins:
- local: [go, run, google.golang.org/protobuf/cmd/protoc-gen-go@v1.36.11]
out: gen
Expand Down
8 changes: 5 additions & 3 deletions conformance/hostgateway/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,11 @@ Since host `af5cef9a` (module-saas-starter#1120, in v0.0.103) the three mints
are served on the gateway's workload endpoint alone and answer 404 on the
public one, so the harness serves the gateway through the host's own
`workloadListener`, as a native run's workload server does. A cell wraps that
listener in a waypoint-authenticated presenter check the SDK never sees, and
which is not under test here. The same commit dropped the internal token from
the work-context mint — that endpoint is its perimeter — and relays accounts'
listener in a waypoint-authenticated presenter check. The conformance suite
uses the host's own authenticated listener and presenter fixtures to check
missing, forged and duplicate assertions, forwarding of the trusted presenter,
and refusal on the public listener. The same commit dropped the internal token
from the work-context mint — that endpoint is its perimeter — and relays accounts'
`Unauthenticated` there as 401 (`ErrInvalidCredentials`), as it already did
`PermissionDenied`. The two operation mints still hold the internal token.

Expand Down
1 change: 1 addition & 0 deletions conformance/hostgateway/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ expected=(
TestSDKConformanceThreeMints
TestSDKConformanceTokenBound
TestSDKConformanceWrongInternalToken
TestSDKConformanceWorkloadPresenter
)

# The modules whose version changes what the gateway under test does. Any
Expand Down
Loading