fix(ci): publish container under token account namespace
This commit is contained in:
1 parent
c389c3893d
commit
867113d5d4
5 files changed
+35
-6
No files matched your search
@@ -98,6 +98,7 @@ jobs:
|
||||
env:
|
||||
REGISTRY_SERVER: ${{ gitea.server_url }}
|
||||
REGISTRY_REPOSITORY: ${{ gitea.repository }}
|
||||
REGISTRY_NAMESPACE: ${{ vars.CONTAINER_REGISTRY_NAMESPACE }}
|
||||
REGISTRY_USER: ${{ secrets.CONTAINER_REGISTRY_USER }}
|
||||
REGISTRY_TOKEN: ${{ secrets.CONTAINER_REGISTRY_TOKEN }}
|
||||
run: bash scripts/publish-container.sh
|
||||
@@ -29,6 +29,7 @@ jobs:
|
||||
env:
|
||||
REGISTRY_SERVER: ${{ gitea.server_url }}
|
||||
REGISTRY_REPOSITORY: ${{ gitea.repository }}
|
||||
REGISTRY_NAMESPACE: ${{ vars.CONTAINER_REGISTRY_NAMESPACE }}
|
||||
REGISTRY_USER: ${{ secrets.CONTAINER_REGISTRY_USER }}
|
||||
REGISTRY_TOKEN: ${{ secrets.CONTAINER_REGISTRY_TOKEN }}
|
||||
run: bash scripts/publish-container.sh
|
||||
@@ -219,9 +219,19 @@ After changing `.env`, recreate the container; an image rebuild is not required.
|
||||
|
||||
To publish from Gitea:
|
||||
|
||||
Gitea packages belong to an account or organization, independently of repository
|
||||
permissions. Publication defaults to the lowercase `CONTAINER_REGISTRY_USER`
|
||||
namespace, so a Simo token publishes `simo/epicnext-cms` even though the Git
|
||||
repository belongs to remco. Set the Actions variable
|
||||
`CONTAINER_REGISTRY_NAMESPACE` only to override this (for example, an organization
|
||||
where the token account has package write access). Keep the login username and
|
||||
token from the same account. Changing namespace also changes the image URL used
|
||||
by installations; existing remco image tags are not moved automatically.
|
||||
|
||||
1. In the repository's Actions secrets, configure `CONTAINER_REGISTRY_USER` and
|
||||
`CONTAINER_REGISTRY_TOKEN`. Use a Gitea access token with package read/write
|
||||
permission belonging to an account allowed to publish under the repository owner.
|
||||
permission belonging to the login account. For the Simo token, set
|
||||
`CONTAINER_REGISTRY_USER=Simo`; the default package namespace will be `simo`.
|
||||
2. Every push to `main` or `master` automatically builds and publishes the images
|
||||
after the CI checks and production deployment succeed. Pull requests do not
|
||||
publish images. The publication job builds from committed source only and checks
|
||||
@@ -235,12 +245,12 @@ To publish from Gitea:
|
||||
migrations image is used temporarily for the matching database migrations.
|
||||
|
||||
For this repository the image base is
|
||||
`gitlab.epicnabbo.nl/remco/epicnext-cms`. Package access is controlled by Gitea.
|
||||
`gitlab.epicnabbo.nl/simo/epicnext-cms`. Package access is controlled by Gitea.
|
||||
For private packages, run `docker login gitlab.epicnabbo.nl` on the installation
|
||||
with a token that can read packages. Then update with:
|
||||
|
||||
```bash
|
||||
CMS_IMAGE_REPOSITORY=gitlab.epicnabbo.nl/remco/epicnext-cms \
|
||||
CMS_IMAGE_REPOSITORY=gitlab.epicnabbo.nl/simo/epicnext-cms \
|
||||
CMS_PUBLIC_URL=https://your-hotel.example \
|
||||
bash scripts/docker-update.sh
|
||||
```
|
||||
|
||||
@@ -11,6 +11,12 @@ registry="${registry%/}"
|
||||
[[ "$REGISTRY_SERVER" = https://* && "$registry" != */* ]] || { echo "Registry must use HTTPS at the Gitea server root" >&2; exit 1; }
|
||||
repository="${REGISTRY_REPOSITORY,,}"
|
||||
[[ "$repository" =~ ^[a-z0-9._-]+/[a-z0-9._-]+$ ]] || exit 1
|
||||
# Gitea packages belong to a user/organization, independently of repository ACLs.
|
||||
# A collaborator token cannot publish to another user's personal namespace.
|
||||
namespace="${REGISTRY_NAMESPACE:-$REGISTRY_USER}"
|
||||
namespace="${namespace,,}"
|
||||
[[ "$namespace" =~ ^[a-z0-9][a-z0-9._-]*$ ]] || { echo "Invalid registry namespace; use a Gitea username or organization" >&2; exit 1; }
|
||||
repository="$namespace/${repository#*/}"
|
||||
image="$registry/$repository:$sha"
|
||||
# Isolate credentials from the self-hosted runner's normal Docker configuration.
|
||||
export DOCKER_CONFIG
|
||||
|
||||
@@ -17,7 +17,7 @@ const bash =
|
||||
.find((path) => existsSync(path)) ?? "bash")
|
||||
: "bash";
|
||||
const sha = "a".repeat(40);
|
||||
function simulate(scenario: string) {
|
||||
function simulate(scenario: string, namespace = "") {
|
||||
const dir = mkdtempSync(join(tmpdir(), "cms-publish-test-"));
|
||||
try {
|
||||
const result = spawnSync(
|
||||
@@ -35,7 +35,8 @@ function simulate(scenario: string) {
|
||||
SCENARIO: scenario,
|
||||
REGISTRY_SERVER: "https://registry.invalid",
|
||||
REGISTRY_REPOSITORY: "owner/cms",
|
||||
REGISTRY_USER: "fixture",
|
||||
REGISTRY_USER: "Simo",
|
||||
REGISTRY_NAMESPACE: namespace,
|
||||
REGISTRY_TOKEN: "fixture-only",
|
||||
},
|
||||
},
|
||||
@@ -51,7 +52,7 @@ describe("verified application image reuse", () => {
|
||||
it("reuses only the exact image digest that passed deployment checks", () => {
|
||||
const calls = simulate("verified");
|
||||
expect(calls).toContain(
|
||||
`docker tag sha256:candidate registry.invalid/owner/cms:${sha}`,
|
||||
`docker tag sha256:candidate registry.invalid/simo/cms:${sha}`,
|
||||
);
|
||||
expect(calls).not.toContain("docker build --network=host --build-arg");
|
||||
expect(
|
||||
@@ -67,3 +68,13 @@ describe("verified application image reuse", () => {
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("uses the token account namespace instead of the repository owner", () => {
|
||||
const calls = simulate("verified");
|
||||
expect(calls).toContain(`docker push registry.invalid/simo/cms:${sha}`);
|
||||
expect(calls).not.toContain("registry.invalid/owner/cms");
|
||||
});
|
||||
it("supports an explicit organization namespace", () => {
|
||||
const calls = simulate("verified", "My-Org");
|
||||
expect(calls).toContain(`docker push registry.invalid/my-org/cms:${sha}`);
|
||||
});
|
||||
Reference in new issue
Block a user