ipcr-public: a second ipcrd behind Caddy at ipcr-<domain>, plain HTTP, no
pinning, off the admin and CI networks. With PUBLIC_POLICY it serves only
this forge's publisher name, its verified ENS/DNS name and its published
image roots; everything else is 404, pushes 405. So
docker pull ipcr-<domain>/ipns/metadec.eth/ipcr-hello:1.0.0
works on any machine with plain Docker. Switch in the admin page
(config.json "public"), mirrored into published.json for the pages, which
show the public pull lines while it is on.
ipcr 1.5.0, bridge 0.4.0. Verified from a second machine (docs/forge.md).
Short names: the public repositories of one Gitea organisation (IPCR_ROOT_ORG,
then the admin page; metadec on our boxes) are also published at the root of
the forge's name, so ipcr.localhost:4767/ipns/metadec.eth/ipcr-hello:1.0.0
works. Collisions (a user/org of that name, another owner's folder) are
skipped and explained.
Push credentials: the staging registry now sits behind forge-gate
(ipcr-forge-bridge gate), in the CI daemon's network namespace, with the
registry on a unix socket and no network. Each publishing repository logs in
as <owner>/<repo> with an IPCR_PUSH_TOKEN Actions secret the bridge sets, and
may push its own name only; IPCR logs in with a credential it generates.
Workflows need a docker/login-action step (example and page updated).
ipcr 1.4.0: allow.aliases with per-pass alias sync; unpublish/retag on every
path; IMPORT_AUTH_GENERATE; names this node publishes resolve via
name/resolve --nocache (Kubo's resolve cache lagged, and the generic resolve
ignores nocache).
bridge 0.3.0: gate, push credentials (rotate in the admin page), root
organisation setting, setup creates the org and the example in it; the
Radicle description carries the Gitea path (identical documents gave the same
RID); OAuth2 app updated only when hosts change, keeping the new secret.
Admin page: tabs, one-line keys, name-check feedback, per-tag docker pull
commands (IPFS, IPNS, ENS, short path first).
Verified on holyhorse (docs/forge.md).
ipcr 1.3.0 (gateway/):
- admin API on ADMIN_LISTEN (Bearer token in STATE_DIR/admin-token):
status (key, node, storage, IPNS record here and on the network via
delegated routing, ENS/DNSLink name check), providers/announce, peers,
images, unpublish (tombstone + unpin unused objects), retag, reimport,
config (name, allowlist), republish, key import (restore with
sequence = max(network, local) + 1; previous key kept, kept copies reused)
- watcher refactored into shared state; config.json with an allowlist
(IMPORT_ALLOW_REQUIRED); staging cleanup after publish (IMPORT_CLEANUP)
- IPNS records published with IPNS_LIFETIME / IPNS_TTL; superseded trees
unpinned
- encrypted publisher-key backups (PBKDF2 + AES-256-GCM), ipcrd key decrypt
bridge 0.2.0 (bridge/):
- /admin: Gitea OAuth2 login (PKCE, site admins only), signed session,
same-origin + X-IPCR-Admin on writes; setup registers the OAuth2 app
- admin page: publisher name and ENS/DNS check, health, published images,
per-repository publish toggles (pushed to IPCR as its allowlist), key
export (from Kubo's keystore, encrypted) and restore
- public page pull lines use the verified name
Compose: ipcr-admin internal network, keystore mount, 7-day IPNS lifetime,
staging GC at registry start. Verified on holyhorse (docs/forge.md).
- forge-runner: 1G (act_runner was OOM-killed mid-job at 256M)
- bridge: log rad's stdout on failure; page links Gitea from its own host
(html_url is the internal address); description fallback without it
- docs/forge.md: holyhorse verification and findings 11-14
Users found Radicle-as-source unfriendly (v1, v2). Gitea is now where
people work; its Actions build images into the staging registry IPCR
follows, as in v2.
- bridge/: ipcr-forge-bridge (Go). Install step mints a public-only
token, registers one system webhook and creates the ipcr-hello example;
the service mirrors every public repo one way to Radicle (rad init,
canonical tags rule, git push rad) and serves the forge's page.
- Compose: gitea + act_runner on a separate dind; tile opens Gitea;
tips link the forge page.
- Removed the Radicle CI broker (ci/) and the nginx landing page.
Snapshot of the Radicle-only forge (cib + act, DinD staging registry)
before the Gitea-centric v3 POC replaces it. Also carries the gateway's
IMPORT_PUBLISHER mode, multi-segment IPNS paths and IPCR 1.2.0.
Following the page end to end on a fresh demo box found four gaps:
- rad init needs a Git repository with a commit: show git init/add/commit
- the node must be running: rad node start
- rad seed ends with "✗ Target not met" from the public seeds; harmless,
check the Radicle explorer instead
- the first build takes 5-10 min while the runner pulls its images
Also say to commit the workflow before tagging.
Found on a fresh install (demostaging1): the Forge pinned bridge 0.1.0,
which predates IPCR_AUTH_FILE, so IPCR's read-only Gitea token was never
written. And ipcr-gateway (root, cap_drop ALL) could not read the token
anyway: it is 0600, owned by $PUID, in a 0700 folder. Bump both bridge
refs to 1.0.0 and give the gateway back DAC_READ_SEARCH (read-only),
documented in rationale.md.
The rename left lowercase paths that 404 on case-sensitive hosts: the
install URLs in the README and on the IPCR Forge landing page, and the
dev compose's ./apps/IPCR/seed mount.