picatz / picatz/flowstate

Design: flow login, profiles, and the attestable identity chain from GHA to Temporal

Open
#110 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

auth cli design kind/design-record
Dominant language
Go
Stars
9
Forks
0
Avg merge
3h 3m
Merged PRs (30d)
509

Description

Two related gaps, one for humans and one for the audit trail — the workload half of the chain already works and is worth stating first so the design builds on it rather than reinventing it.

What is already true

A GitHub Actions job can start a Flowstate workflow today with no stored secret anywhere: the trust policy names GHA's issuer with claim rules (repository, ref, environment — exact-match any_of, deliberately no wildcards), the job presents its OIDC token via FLOWSTATE_TOKEN="$(gha-oidc-token)", the server verifies against GitHub's JWKS, derives the tenant from a claim, records the identity in RunState.Identity and the namespace memo, sets the fairness key, and — since #103 — routes to the mapped Temporal namespace and carries the named claims into the run's WorkloadIdentity. That is GHA → Flowstate → Temporal with the identity attached at every hop. The pieces are coherent; what is missing is the human path and the legibility of the chain.

flow login, and profiles

Today a human authenticates by exporting FLOWSTATE_TOKEN from wherever they can get one (gcloud auth print-identity-token is the documented example), and --token deliberately does not exist (a credential in argv is a credential in ps — keep that refusal). What is missing:

  1. flow login — OAuth device flow against the deployment's configured IdP: the server's discovery document (already published at /.well-known/... when federating) grows the fields a client needs, flow login opens the browser or prints the device code, and the resulting token is cached with 0600 discipline and refreshed while refreshable. Fail-visible: flow login status says who you are, to which deployment, expiring when — the answer to "why am I getting 401" that today requires decoding a JWT by hand.
  2. Profiles, following the precedent already in the repo: the Temporal connection already honours TEMPORAL_PROFILE and the temporal CLI's own TOML — adopting the ecosystem's convention rather than inventing one is recorded as a deliberate choice in ARCHITECTURE.md. Flowstate's client config should take the same shape: a FLOWSTATE_PROFILE selecting {address, auth method, token cache, default namespace} from one file, so flow --profile staging run … and CI's env-var-only path are the same code resolving the same precedence (flags > env > profile > default). One resolution order, documented once, tested once.
  3. Profiles do not hold tokens — they name where tokens come from (an IdP for the device flow, a file for CI, an env var). The cache is per-profile state beside, not inside, the profile.

The attestable chain, end to end

The enterprise question is "who caused this step to call that API, prove it" — and every hop already has the data; the work is making it one legible chain:

  • Inbound attestation: record in the run (not just derive from) the verified issuer, subject, and the claims that were checked — the trust-policy decision, content-addressed like #104 proposes for policies, so "which rules admitted this caller" is answerable after the rules change.
  • Through Temporal: the identity already rides RunState and the memo; Temporal's own RBAC applies below the namespace mapping (#107). A reader of Temporal history sees the same identity Flowstate enforced — no parallel truth.
  • Outbound attestation: #94's assertions already carry on_behalf_of / on_behalf_of_issuer plus the per-step subject (flowstate:<ns>/<deployment>/<workflow>/<step>) — so the STS session at AWS names the workload and the CI job that asked for it, with the hashed session-name discipline from #75 preventing tenant spoofing. When #94 wires the broker into activities, the chain closes: GHA job → Flowstate run → step → cloud credential, every link signed, short-lived, and audience-scoped, no standing secret at any hop.
  • flow trace-shaped legibility (the fourth-round CLI doctrine already names it): one command answering the whole chain for a run — who started it, under which trust rules, which identities each step assumed, against which policies — from data the run already carries rather than a SIEM expedition.

Constraints

Invariant 8: all of it optional — --insecure-no-auth local development keeps working with zero configuration, and flow login against a deployment with no IdP configured says so plainly. The device-flow secret handling follows the secrets discipline (cached token never logged, never in argv, 0600, containment-shape tested). Admin surface for managing trusted issuers at runtime is #107's; this issue is the client half and the chain's legibility.

Related: #107 (control plane — issuer management), #94 (outbound federation — the chain's far end), #104 (policy digests — the "under which rules" attestation), #93/#103 (the inbound wiring this builds on).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with ARCHITECTURE.md and the existing TEMPORAL_PROFILE and Temporal CLI configuration precedent. Map the entry points for flow login, flow login status, profile resolution, and flow trace, then review the related work in #93, #103, #104, #107, and #94. Done means an agreed design covering human login, profile precedence, and a legible attested chain without weakening the stated constraints.

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, github-actions, go
Domain
authentication, cli, cloud, distributed-systems, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.