IPCR Forge: org-root image names and per-repository push credentials
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).
This commit is contained in:
+13
-2
@@ -4,6 +4,7 @@
|
||||
// serve (default) webhook receiver + mirror worker + the forge's page
|
||||
// setup install step: Gitea token, system webhook, example repository (idempotent)
|
||||
// health exit 0 when `serve` answers, for the container healthcheck
|
||||
// gate the staging registry's front door: per-repository push credentials (gate.go)
|
||||
//
|
||||
// What gets mirrored: every public, non-fork, non-mirror Gitea repository, as seen by a token
|
||||
// scoped `public-only` — a private repository is invisible to the service, not filtered by it.
|
||||
@@ -39,6 +40,10 @@
|
||||
// IPCR_ADMIN_TOKEN_FILE its token (default /srv/ipcr-state/admin-token)
|
||||
// KUBO_KEYSTORE Kubo's keystore, read-only, for key backups (default /srv/ipcr-keystore)
|
||||
// IMPORT_PUBLISHER the publisher key's name (default forge)
|
||||
// IPCR_ROOT_ORG organisation published at the root of the forge's name, until changed in
|
||||
// the admin page (default: none)
|
||||
// GATE_CREDENTIALS the gate's credentials.json (default /bridge/gate/credentials.json)
|
||||
// IPCR_STAGING_AUTH IPCR's own staging credential (default /srv/ipcr-state/staging-auth)
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -71,8 +76,10 @@ func main() {
|
||||
err = setup()
|
||||
case "health":
|
||||
err = health()
|
||||
case "gate":
|
||||
err = gateMain()
|
||||
default:
|
||||
err = fmt.Errorf("usage: %s serve | setup | health", os.Args[0])
|
||||
err = fmt.Errorf("usage: %s serve | setup | health | gate", os.Args[0])
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
@@ -128,10 +135,14 @@ func serve() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
adminGitea := newGitea(m.gitea.base, m.gitea.owner, secrets+"/gitea-admin-token")
|
||||
adm := &adminAPI{
|
||||
ipcr: strings.TrimRight(ipcr, "/"), tokenFile: env("IPCR_ADMIN_TOKEN_FILE", "/srv/ipcr-state/admin-token"),
|
||||
keystore: env("KUBO_KEYSTORE", "/srv/ipcr-keystore"), publisher: env("IMPORT_PUBLISHER", "forge"),
|
||||
settings: stateDir + "/admin.json", gitea: m.gitea, http: &http.Client{Timeout: 3 * time.Minute},
|
||||
settings: stateDir + "/admin.json", gitea: m.gitea, admin: adminGitea, rootOrg: os.Getenv("IPCR_ROOT_ORG"),
|
||||
creds: &pushCreds{file: env("GATE_CREDENTIALS", stateDir+"/gate/credentials.json"),
|
||||
stagingAuth: env("IPCR_STAGING_AUTH", "/srv/ipcr-state/staging-auth"), gitea: adminGitea},
|
||||
http: &http.Client{Timeout: 3 * time.Minute},
|
||||
}
|
||||
adminRoutes(mux, au, adm)
|
||||
// IPCR publishes nothing until it has the list (IMPORT_ALLOW_REQUIRED): send it as soon as
|
||||
|
||||
Reference in New Issue
Block a user