Skip to content

Commit e76be91

Browse files
committed
Publish snapshot (2026-09-08)
1 parent 2df489a commit e76be91

1,370 files changed

Lines changed: 229780 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.dockerignore‎

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Shared .dockerignore — trims the Docker build context aggressively so
2+
# every service Dockerfile starts with just the source it needs.
3+
.git
4+
.github
5+
.gitlab
6+
.beads
7+
.contextgit
8+
.claude
9+
.devstack
10+
.gocache
11+
.idea
12+
.vscode
13+
.DS_Store
14+
*.md
15+
!proto/CHANGELOG.md
16+
17+
# Build output
18+
bin/
19+
dist/
20+
logs/
21+
22+
# Virtualenvs + caches
23+
.venv
24+
**/__pycache__/
25+
**/.ruff_cache/
26+
**/.mypy_cache/
27+
**/.pytest_cache/
28+
**/node_modules/
29+
**/.wrangler/
30+
**/.turbo/
31+
32+
# src/edge/ is shared with the fastly-edge image which imports @fora/edge;
33+
# only exclude generated outputs, not the source.
34+
src/edge/node_modules/
35+
src/edge/dist/
36+
src/edge/.wrangler/
37+
src/mcp/.venv/
38+
src/mcp/**/__pycache__/
39+
40+
# Legacy / paused workstreams (not needed in any container)
41+
docs/
42+
pkg/
43+
# scripts/ stays out of build contexts EXCEPT the shared key helpers, which
44+
# the publisher-jwks image copies in so its entrypoint renders the WBA
45+
# directory through the same module the key-gen scripts use.
46+
scripts/*
47+
!scripts/lib/
48+
scripts/lib/*
49+
!scripts/lib/ed25519_keys.py
50+
analysis/
51+
analysis-*
52+
ec-br-*
53+
mathweb/
54+
# tests/ is mostly unused by service images, but tests/e2e/ IS needed by
55+
# the runner image. Exclude everything under tests/ except tests/e2e/.
56+
tests/*
57+
!tests/e2e/
58+
59+
# Large binary assets
60+
FORA*.pdf
61+
*.pdf
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# Builds the three FORA service images and publishes them to the GitHub
2+
# Container Registry.
3+
#
4+
# WHAT STARTS IT. A tag whose name begins with "v", pushed to this repository,
5+
# or a manual run from the Actions tab. Publishing source and publishing images
6+
# are deliberately separate acts: a source snapshot on its own builds nothing,
7+
# so a documentation-only update never reissues the images.
8+
#
9+
# A manual run must select a TAG as its ref, not a branch. The version comes from
10+
# the tag and there is nowhere else to get it; a branch produces no version at
11+
# all, and the first step below stops the run rather than letting it fail later
12+
# with something less obvious.
13+
#
14+
# AUTHENTICATION. The per-run GITHUB_TOKEN and nothing else. No personal access
15+
# token is created, stored or rotated for this workflow.
16+
#
17+
# TAGS. Exactly one per build: the version from the git tag with the leading "v"
18+
# removed. There is no "latest" and no moving major or minor pointer, so a
19+
# published tag names one build for ever. Production should pin by digest
20+
# (@sha256:...), which every image carries whether or not it is tagged.
21+
#
22+
# ARCHITECTURE. linux/amd64 only. The Broker and the Identity service are pure
23+
# Go and would need no more than the extra platform here, but the Exchange links
24+
# a C library for the ledger client, so an x86 runner cannot build its arm64
25+
# variant. Adding ARM means an arm64 runner and a manifest merge.
26+
#
27+
# Third-party actions are pinned by commit rather than by tag, because whoever
28+
# owns an action can repoint its tags at any time.
29+
30+
name: Publish container images
31+
32+
on:
33+
push:
34+
tags:
35+
- "v*"
36+
workflow_dispatch:
37+
38+
permissions:
39+
contents: read
40+
packages: write
41+
42+
concurrency:
43+
# One publish per ref at a time, and never cancel a run that is under way. A
44+
# half-finished release leaves some of the three images published and some
45+
# not, which is worse than a slow queue.
46+
group: publish-images-${{ github.ref }}
47+
cancel-in-progress: false
48+
49+
jobs:
50+
publish:
51+
runs-on: ubuntu-24.04
52+
strategy:
53+
# The three build independently. One failure must not hide the other two
54+
# results, which is exactly what you need when a release breaks.
55+
fail-fast: false
56+
matrix:
57+
include:
58+
- service: exchange
59+
dockerfile: src/exchange/Dockerfile
60+
- service: broker
61+
dockerfile: src/broker/Dockerfile
62+
- service: identity
63+
dockerfile: src/identity/Dockerfile
64+
65+
steps:
66+
- name: Check out the source
67+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
68+
69+
- name: Set up Buildx
70+
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
71+
72+
- name: Sign in to the registry
73+
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
74+
with:
75+
registry: ghcr.io
76+
username: ${{ github.actor }}
77+
password: ${{ secrets.GITHUB_TOKEN }}
78+
79+
- name: Derive the image tag
80+
id: meta
81+
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
82+
with:
83+
# Lower case throughout: the registry refuses a mixed-case name.
84+
images: ghcr.io/fora-protocol/${{ matrix.service }}
85+
# This list REPLACES the action's default rules. Keep it to the single
86+
# entry: a default rule would publish tags that move.
87+
tags: |
88+
type=semver,pattern={{version}}
89+
# Needed as well. The "latest" flavour defaults to "auto", which adds
90+
# a latest tag on its own as soon as the ref is a version tag.
91+
flavor: |
92+
latest=false
93+
94+
- name: Refuse a run that has no version to publish
95+
# A manual run can select any ref. On a branch the semver rule above
96+
# matches nothing, so the tag list comes out empty. Without this step the
97+
# build compiles all the way through and then fails inside the push, and
98+
# the message it fails with does not say "you picked a branch".
99+
#
100+
# The ref reaches the script through the environment, never through an
101+
# expression. GitHub substitutes an expression into the script TEXT
102+
# before bash reads it, so at that point a ref name is command text.
103+
# A ref name may hold $, backticks, parentheses, ; & and |. git does
104+
# reject some characters — spaces, backslashes, control characters, and
105+
# the revision syntax it needs for itself, : ? * [ ~ ^ — but not one of
106+
# those omissions closes this hole. The job holds a token with
107+
# packages: write for all three images.
108+
#
109+
# The message names no version. The tag is the only source of one, so an
110+
# example here would be a second place to edit at release time, and the
111+
# last one anybody would think to check.
112+
if: steps.meta.outputs.tags == ''
113+
env:
114+
TRIGGER_REF: ${{ github.ref }}
115+
run: |
116+
echo "::error::No version tag was derived from ${TRIGGER_REF}. The version comes from the tag name and nowhere else: run this workflow against a tag whose name is the version to publish, with a leading v."
117+
exit 1
118+
119+
- name: Build and push
120+
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
121+
with:
122+
# The repository root, because every service Dockerfile also copies
123+
# the shared internal/ tree.
124+
context: .
125+
file: ${{ matrix.dockerfile }}
126+
platforms: linux/amd64
127+
push: true
128+
tags: ${{ steps.meta.outputs.tags }}
129+
# Only the two labels that cannot be known until the build runs. The
130+
# rest — source, licenses, title, description — are baked into each
131+
# Dockerfile, and passing the metadata action's full label set here
132+
# would overwrite the per-service title and description with this
133+
# repository's own name for all three images. There is no created
134+
# label because the image config already records a creation time.
135+
labels: |
136+
org.opencontainers.image.version=${{ steps.meta.outputs.version }}
137+
org.opencontainers.image.revision=${{ github.sha }}
138+
# Off on purpose. With provenance on, the pushed tag resolves to an
139+
# image index carrying an extra attestation entry, which is a
140+
# multi-platform manifest in everything but name. One platform is
141+
# published, so the tag should resolve straight to that one image.
142+
provenance: false
143+
# Without a cache every run recompiles Go from cold, several minutes
144+
# per service. The scope keeps the three from evicting each other.
145+
cache-from: type=gha,scope=${{ matrix.service }}
146+
cache-to: type=gha,mode=max,scope=${{ matrix.service }}

‎.gitignore‎

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
node_modules/
2+
dist/
3+
.wrangler/
4+
.dev.vars
5+
.env
6+
.env.local
7+
8+
# RFC 9421 demo agent private key — generated at bootstrap, never committed.
9+
deploy/mcp/agent-key.json
10+
# RFC 9421 broker-relay private key — generated at bootstrap, never committed.
11+
deploy/broker/broker-key.json
12+
13+
# No Ed25519 private-key material under deploy/ may be re-committed.
14+
# Demo/contributor/publisher signing keys are generated at bootstrap (see
15+
# scripts/gen-*-key.sh) and mounted at runtime. This broad pattern blocks any
16+
# accidental re-add of a *key*.json under deploy/.
17+
# If demo fixture CONTENT ever needs a name containing "key" (say a
18+
# typewriter-keystroke sound-effect file), re-include exactly that file by its
19+
# full path — never a subtree pattern, which would make any agent-key.json
20+
# placed under the tree committable.
21+
deploy/**/*key*.json
22+
!deploy/content/demo/foleyworks/sfx/typewriter-keystroke.json
23+
24+
# The E2E harness private signing fixtures are generated at
25+
# bootstrap (scripts/gen-e2e-keys.sh, wired into `make e2e-up`) and never
26+
# committed. This blocks any accidental re-add of private key material under
27+
# the harness fixtures dir.
28+
tests/e2e/harness/fixtures/*_key.json
29+
tests/e2e/**/*key*.json
30+
# Per-edge MANIFEST_PUBLIC_KEYS_JSON env_files (PUBLIC keys only) are
31+
# generated at bootstrap by gen-e2e-keys.sh from the same private fixtures and
32+
# injected into the demo edges via env_file. Generated material — not committed.
33+
deploy/edge-keys/*.env
34+
*.tsbuildinfo
35+
coverage/
36+
.turbo/
37+
.code-review/
38+
39+
# Go
40+
bin/
41+
*.test
42+
*.out
43+
.gocache/
44+
45+
# Python (mcp-tool)
46+
__pycache__/
47+
*.pyc
48+
.venv/
49+
*.egg-info/
50+
.mypy_cache/
51+
.ruff_cache/
52+
.pytest_cache/
53+
54+
# jscpd reports
55+
logs/jscpd/
56+
57+
# devstack per-project state (random ports, volume IDs)
58+
.devstack/
59+
60+
# Secrets
61+
*.key
62+
*.pem
63+
64+
# OS
65+
.DS_Store
66+
Thumbs.db
67+
68+
# Editor
69+
.idea/
70+
.vscode/
71+
*.swp
72+
*.swo
73+
.aider*
74+
75+
# Claude Code harness — per-spawn worktrees from Agent tool isolation: "worktree"
76+
.claude/worktrees/
77+
.claude/scheduled_tasks.lock
78+
# Local code-review runs: transient reports that quote the tree verbatim, so they
79+
# preserve whatever the source said at the time — including names a later sweep
80+
# removed. They belong on disk, never in git.
81+
.claude/code-review/
82+
83+
# Runtime logs and ephemeral reports
84+
logs/
85+
.jscpd-reports/
86+
87+
# Stale Go build artifacts at repo root (none should land here)
88+
/prototype
89+
/entitlement-mint
90+
91+
# Compiled service binaries (go build output lands next to main.go as the dir
92+
# name, e.g. src/broker/cmd/server/server). These are build artifacts, never
93+
# committed — a 33 MB binary was previously committed by accident.
94+
**/cmd/server/server
95+
96+
# Scratch output from the requirements-derivation tooling, which is not part of
97+
# this repository. Ignored so a stray local run cannot be committed.
98+
.derive-ensemble/
99+
derive-ensemble/
100+
101+
.perles
102+
103+
# Beads / Dolt files (added by bd init)
104+
.dolt/
105+
*.db
106+
.beads-credential-key
107+
108+
# Obsidian editor workspace (local-only, not part of the docs source)
109+
docs/.obsidian/
110+
111+
# Runtime artifact written by the cross-container revocation e2e (test_revocation_channel).
112+
tests/e2e/harness/revocations/revocations.json
113+
114+
# Beads: the Dolt server is the source of truth. .beads/metadata.json was
115+
# git-tracked, so a branch checkout restored its pre-Dolt SQLite stub and bd
116+
# silently opened an empty database — hiding all 5279 issues. Never track it.
117+
.beads/

0 commit comments

Comments
 (0)