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
12 changes: 10 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,16 @@ Fleet standard — [handbook#68](https://github.com/obin-ai/handbook/issues/68).
- **Never hardcode what the system resolves** — injected environment, derived
ports, service addresses, credentials copied out of another component. This
SDK is on the resolving side of that line: a facade takes a gateway and reads
`BaseURL()` off it rather than holding a URL, and `moduleauthority` takes
both seams from the consumer rather than defaulting either. Typing one of those in encodes something true
`BaseURL()` off it rather than holding a URL. `moduleauthority` takes its
gateway and authority seams from the consumer and defaults neither address:
a zero `Authority` builds a mint-only client that fails with
`ErrNoAuthority`, never one that dials an address nobody configured. The one
value it does resolve is a credential source the consumer opts into, the
projected token's path: `WorkloadTokenFile()` reads it from the variable a
native run injects (`CODEFLY__WORKLOAD_TOKEN_FILE`) and otherwise falls back
to the mount a cell's render declares, and a consumer whose path comes from
elsewhere passes `ProjectedTokenFile(path)`, which has no default. Typing one
of those in encodes something true
on one machine for ten minutes, and it fails quietly — a runtime missing a
credential can skip registration *silently*, so the service boots, serves,
and is simply absent.
Expand Down
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@
the mount minted nothing there. The variable and the path are exported as
`WorkloadTokenFileVariable` and `PodWorkloadTokenFile`;
codefly-dev/solution-runtime-go reads the same variable. It resolves the
path only: the token is still read before every mint.
path only: the token is still read before every mint. Its scope is the
services a native run names the variable for — `module-identity` without
`workload-identity`; a `workload-identity` service receives its path as
`TOKEN_FILE` in its `workload-identity` configuration and passes
`ProjectedTokenFile(path)` itself.

## v0.1.2 — core v0.19.1; Work Contexts are core's, carried opaque

Expand Down
19 changes: 12 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,13 +292,18 @@ The SDK surfaces are:
`AllowInsecureHTTP` asserts the hop is mesh-protected. SaaS owns the installed
binding's audience, scopes, lifetime, verification, and audit record.

`WorkloadTokenFile()` is where Codefly projected the token for the process
it runs: the file `CODEFLY__WORKLOAD_TOKEN_FILE` names when that is set —
a native `codefly run` (CLI v0.1.187 and later) stands in for the cell and
projects each module's token to a file of its own, since a process cannot
read the pod mount — and the pod mount, `/var/run/secrets/codefly/token`,
otherwise. A consumer with another projection passes
`ProjectedTokenFile(path)` instead, which has no default. The host requires audience
`WorkloadTokenFile()` is where Codefly projected the token for a
module-identity service: the file `CODEFLY__WORKLOAD_TOKEN_FILE` names when
that is set, and the pod mount, `/var/run/secrets/codefly/token`, otherwise.
A native `codefly run` (CLI v0.1.187 and later) stands in for the cell and
projects each such service's token to a file of its own, since a process
cannot read the pod mount, but it sets that variable only for a service that
declares `module-identity` and does **not** declare `workload-identity`. A
`workload-identity` service gets its token's path as `TOKEN_FILE` in its
`workload-identity` configuration instead, so for it the helper falls back
to the pod path, which does not exist under a native run; it passes
`ProjectedTokenFile(path)` with that configured path. A consumer with any
other projection does the same; `ProjectedTokenFile` has no default. The host requires audience
`accounts` and a token lifetime of at most 600 seconds, and verifies the pod,
workload and approved build. The SDK rereads the source for every actual mint
(including a module Work Context refresh), trims whitespace, and rejects an
Expand Down
2 changes: 1 addition & 1 deletion moduleauthority/broker_transport_errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ func brokerParserTransport(t *testing.T, wire string) *http.Transport {
done := make(chan struct{})
go func() {
defer close(done)
defer server.Close()
defer func() { _ = server.Close() }()
req, err := http.ReadRequest(bufio.NewReader(server))
if err != nil {
return
Expand Down
23 changes: 17 additions & 6 deletions moduleauthority/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,9 @@ type ProjectedTokenSource interface {
// one exists because moduleauthority does not import sdk-go/workcontext: it
// carries Work Contexts as opaque strings and reads them only through core.
//
// A module running under Codefly passes WorkloadTokenFile(), which names the
// path Codefly projected the token to wherever it runs.
// A module-identity service running under Codefly passes WorkloadTokenFile(),
// which names the path Codefly projected its token to in a cell's pod and in
// a native run; see WorkloadTokenFile for the one case it does not cover.
type ProjectedTokenFile string

// WorkloadTokenFileVariable is the environment variable that names the
Expand All @@ -180,10 +181,20 @@ const WorkloadTokenFileVariable = "CODEFLY__WORKLOAD_TOKEN_FILE"
// projected ServiceAccount token at, read-only, for audience `accounts`.
const PodWorkloadTokenFile = "/var/run/secrets/codefly/token"

// WorkloadTokenFile is where this module's projected token is, wherever
// Codefly runs it: the file WorkloadTokenFileVariable names when the variable
// is set to a non-blank value, and PodWorkloadTokenFile otherwise. A process
// under a native run is told; a pod is not, and reads its mount.
// WorkloadTokenFile is where a module-identity service's projected token is:
// the file WorkloadTokenFileVariable names when the variable is set to a
// non-blank value, and PodWorkloadTokenFile otherwise. A process under a native
// run is told; a pod is not, and reads its mount.
//
// Its scope is exactly the services a native run names the variable for: a
// service that declares module-identity and does not declare
// workload-identity (codefly-dev/cli cmd/run/native_cluster.go). A service
// that declares workload-identity is not given the variable; a native run
// delivers its token's path as TOKEN_FILE in its workload-identity
// configuration instead, so for it this helper falls back to
// PodWorkloadTokenFile, a path that does not exist on the machine running it.
// Such a service passes ProjectedTokenFile with the path that configuration
// names.
//
// It resolves the path, never the token: the file is still read before every
// mint, because the projection rotates under a running process.
Expand Down
Loading