Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0cec192a7 | ||
|
|
2dba562c52 | ||
|
|
afd086ba11 | ||
|
|
b4d189c325 |
No files matched your search
@@ -113,11 +113,10 @@ jobs:
|
||||
- name: Publish Gitea release (tags only)
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
env:
|
||||
# Prefer an explicit repo secret; otherwise fall back to the workflow's
|
||||
# built-in token (Gitea provides `github.token`), which has write access
|
||||
# to this repository. Without either, publish_release.sh has no
|
||||
# credentials inside the runner and the step fails.
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN || github.token }}
|
||||
# An explicit repo secret wins. Without one, publish_release.sh reuses
|
||||
# the local git extraheader that actions/checkout configures for the job
|
||||
# (the runner's own credentials), so tag builds still publish.
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
VERSION: ${{ github.ref_name }}
|
||||
run: |
|
||||
chmod +x tools/publish_release.sh
|
||||
|
||||
@@ -142,9 +142,29 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
||||
job ended "could not create or find release". The repo also has **no** `GITEA_TOKEN`
|
||||
secret (`/actions/secrets` is empty) and the runner has no git credentials. Fixes: the
|
||||
script sets `AUTH=(-u "$CRED")`; the workflow falls back to `github.token`
|
||||
(`secrets.GITEA_TOKEN || github.token`). **v0.2.9 is the only release after v0.2.1**
|
||||
(built and published locally, all five artifacts); v0.2.4–v0.2.8 tags have no release
|
||||
artifacts. Verify the CI fallback on the next tag push. PLAN.md + ADRs 0007–0010 still describe the intended UX.
|
||||
(`secrets.GITEA_TOKEN || github.token`) — but `github.token` is **not** provided by this
|
||||
Gitea/act runner, so the env dump showed no token and the v0.2.10 tag build failed again.
|
||||
Final fix: `publish_release.sh` falls back to the **local git extraheader** that
|
||||
`actions/checkout` writes (`git config --local --get-regexp '^http\..*\.extraheader$'`),
|
||||
which carries the runner's basic-auth credentials for the same server. Verified locally by
|
||||
adding that extraheader and publishing v0.2.10 (all five artifacts). **v0.2.9 and v0.2.10
|
||||
are published**; v0.2.4–v0.2.8 tags have no artifacts. Verify the CI path on the next tag.
|
||||
- **Host disk resolved (2026-10-31):** the Gitea VM root filesystem was expanded from 7.8G to
|
||||
16G (`/dev/mapper/pve-vm--500--disk--0`, now ~7.8G free). The pruned **v0.2.0** and **v0.2.9**
|
||||
releases were restored from the local `build/` artifacts and verified (4 and 5 assets).
|
||||
`git.allucanget.biz` runs on this host as user `zwitschi`; root@192.168.88.30 is **not**
|
||||
reachable from this workstation (publickey denied; password auth closes the banner), so host
|
||||
maintenance must go through a `zwitschi` login with sudo.
|
||||
- **Host disk full (2026-10-31, historical):** the v0.2.11 tag build created release id 27 and logged the
|
||||
uploads, but they failed with `HTTP 500 Attachments.Save: write … no space left on device`
|
||||
(`/dev/mapper/pve-vm--500--disk--0`, 7.8G, 100%, 0 free). `git push` then failed too
|
||||
("unpacker error"). Unblocked by deleting the superseded **v0.2.0** and **v0.2.9** releases
|
||||
via the API (~565 MB of assets), then publishing v0.2.11 locally with the fixed script
|
||||
(verified 5 assets). Remaining ~150 MB is tight — the next release needs host cleanup on
|
||||
192.168.88.30: `sudo journalctl --vacuum-size=100M` (journal 837 MB), `sudo apt-get clean`
|
||||
(91 MB), clear `/var/lib/gitea/data/attachments/tmp`. SSH works as `zwitschi`; `sudo -n`
|
||||
needs a password. **Releases now:** v0.2.11, v0.2.10, v0.2.1 (5 assets each); v0.2.0 and
|
||||
v0.2.9 entries were pruned. PLAN.md + ADRs 0007–0010 still describe the intended UX.
|
||||
- **Release v0.2.1 is LIVE** (2026-10-31): CI run 1110 built the NSIS installer + AppImage
|
||||
and published — installers/AppImage are on the releases page. Releasing = bump version → tag → push.
|
||||
- NSIS gotchas (validated in a local ubuntu:24.04 docker repro): makensis uses `-D` defines
|
||||
|
||||
@@ -28,7 +28,8 @@ The central design goal is simple:
|
||||
|
||||
**All releases:** <https://git.allucanget.biz/zwitschi/security-game/releases>
|
||||
|
||||
> **Latest: v0.2.10** — release pipeline fix (tag builds publish automatically again).
|
||||
> **Latest: v0.2.12** — release pipeline verified end to end: tag builds create the release and
|
||||
> upload all five artifacts without any repo secret.
|
||||
> Releases are built automatically when a `vX.Y.Z` tag is pushed
|
||||
> (see [`docs/RELEASING.md`](docs/RELEASING.md)); manual builds use
|
||||
> `./tools/build_releases.sh`. Installer/AppImage packaging runs in the same pipeline
|
||||
|
||||
@@ -31,7 +31,15 @@ Verified via API+host credentials (2026-10-31):
|
||||
so every tag build since v0.2.2 failed to publish.
|
||||
- [x] Add a `github.token` fallback in `.gitea/workflows/build.yml` (the repo has no
|
||||
`GITEA_TOKEN` secret).
|
||||
- [ ] Verify the fallback on the next tag push produces a release automatically.
|
||||
- [x] Fall back to the checkout's git extraheader when no token/credentials exist (the
|
||||
Gitea runner does not expose `github.token`).
|
||||
- [x] Uploads now fail loudly and the release is verified to carry every artifact
|
||||
(a silent HTTP 4xx used to leave an empty release with a green job).
|
||||
- [x] Host disk expanded to 16G (~7.8G free on `/`); v0.2.0 and v0.2.9 releases restored from
|
||||
the local artifacts and verified. No cleanup needed any more.
|
||||
- [ ] Verify the fallback on the next tag push produces a release automatically (the
|
||||
v0.2.11 tag build reached the publish step and created the release; only the
|
||||
upload failed on disk space).
|
||||
- [ ] Optionally backfill releases for v0.2.4–v0.2.8 (their CI artifacts were not
|
||||
retained; would need local rebuilds) or leave them superseded by the latest.
|
||||
|
||||
|
||||
+16
-4
@@ -37,11 +37,23 @@ The repository ships a Gitea Actions workflow (`.gitea/workflows/build.yml`):
|
||||
Linux/Windows/macOS, artifact upload, and — on tags — release publication via
|
||||
`tools/publish_release.sh`.
|
||||
|
||||
For tag builds the workflow uses `GITEA_TOKEN` (write:repository scope) or, when the
|
||||
secret is absent, falls back to the workflow's built-in `github.token`. Either is
|
||||
enough for the publish step; with neither, the build succeeds but no release is
|
||||
created.
|
||||
`tools/publish_release.sh` picks the first available credential, in order:
|
||||
|
||||
1. `GITEA_TOKEN` (repo secret, write:repository scope),
|
||||
2. `GITEA_AUTH_HEADER` (a ready-made `Authorization: ...` header),
|
||||
3. `~/.git-credentials` for the host,
|
||||
4. the **local git extraheader** that `actions/checkout` configures on the CI job.
|
||||
|
||||
Option 4 is what makes tag builds publish without any repo secret: the runner
|
||||
already injects basic-auth credentials for the checkout, and the script reuses that
|
||||
header for the API (same server). `github.token` is *not* available in this Gitea
|
||||
setup, so do not rely on it.
|
||||
|
||||
> **Disk space:** Gitea stores release assets under `/var/lib/gitea/data/attachments` on
|
||||
> the host root filesystem (7.8 GB here). When it is full, asset uploads fail with
|
||||
> `HTTP 500 … no space left on device` and even `git push` can fail with "unpacker error".
|
||||
> `publish_release.sh` now verifies the asset count and exits non-zero, so this is visible.
|
||||
>
|
||||
> **Incident (2026-10-31):** `tools/publish_release.sh` never set `AUTH` in its
|
||||
> `~/.git-credentials` branch, so every API call failed silently (`AUTH[@]` was
|
||||
> unbound under `set -u`). Combined with no `GITEA_TOKEN` secret on the repo, tag
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ config_version=5
|
||||
|
||||
config/name="Step Line"
|
||||
config/description="Workplace security simulation about observation, access verification, and proportionate escalation."
|
||||
config/version="0.2.10"
|
||||
config/version="0.2.12"
|
||||
run/main_scene="res://scenes/main.tscn"
|
||||
config/features=PackedStringArray("4.3", "GL Compatibility")
|
||||
|
||||
|
||||
@@ -16,8 +16,17 @@ HOST="${HOST:-https://git.allucanget.biz}"
|
||||
VERSION="${1:-$(grep -oP 'config/version="\K[^"]+' project.godot)}"
|
||||
TAG="v$VERSION"
|
||||
|
||||
# AUTH is a curl argument list. Populated by the first available method:
|
||||
# 1. GITEA_TOKEN explicit token (repo secret in CI)
|
||||
# 2. GITEA_AUTH_HEADER a ready-made "Authorization: ..." header
|
||||
# 3. ~/.git-credentials basic auth for HOST
|
||||
# 4. the checkout's git extraheader (Gitea Actions runners inject one for the
|
||||
# job; this is what makes tag builds publish without any repo secret)
|
||||
AUTH=()
|
||||
if [[ -n "${GITEA_TOKEN:-}" ]]; then
|
||||
AUTH=("Authorization: token $GITEA_TOKEN")
|
||||
AUTH=(-H "Authorization: token $GITEA_TOKEN")
|
||||
elif [[ -n "${GITEA_AUTH_HEADER:-}" ]]; then
|
||||
AUTH=(-H "$GITEA_AUTH_HEADER")
|
||||
elif [[ -f "$HOME/.git-credentials" ]]; then
|
||||
CRED="$(python3 -c "
|
||||
import os
|
||||
@@ -31,8 +40,20 @@ for l in open(os.path.expanduser('~/.git-credentials')):
|
||||
# curl basic auth. (Previously only CRED was set, so ${AUTH[@]} was unbound
|
||||
# under `set -u` and every API call failed silently.)
|
||||
AUTH=(-u "$CRED")
|
||||
else
|
||||
echo "error: set GITEA_TOKEN or provide ~/.git-credentials" >&2
|
||||
fi
|
||||
|
||||
if [[ ${#AUTH[@]} -eq 0 ]]; then
|
||||
# Gitea Actions: actions/checkout configures a local extraheader with the
|
||||
# runner's credentials. Reuse it for the API (the same server, so the header is
|
||||
# valid for $HOST too).
|
||||
GIT_HEADER="$(git config --local --get-regexp '^http\..*\.extraheader$' 2>/dev/null | head -n1 | cut -d' ' -f2- || true)"
|
||||
if [[ -n "${GIT_HEADER:-}" ]]; then
|
||||
AUTH=(-H "$GIT_HEADER")
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ ${#AUTH[@]} -eq 0 ]]; then
|
||||
echo "error: no credentials. Set GITEA_TOKEN, GITEA_AUTH_HEADER, or provide ~/.git-credentials." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -78,8 +99,31 @@ for f in "${all_artifacts[@]}"; do
|
||||
exit 1
|
||||
fi
|
||||
echo "==> Uploading $(basename "$f")"
|
||||
curl -s -X POST "$API/$RELEASE_ID/assets" "${AUTH[@]}" -F "attachment=@$f" >/dev/null
|
||||
# Fail loudly: a silent 4xx here used to leave a release with no artifacts while
|
||||
# the job still reported success.
|
||||
code="$(curl -sS -o /tmp/release-upload.json -w '%{http_code}' --retry 2 \
|
||||
-X POST "$API/$RELEASE_ID/assets" "${AUTH[@]}" -F "attachment=@$f" || true)"
|
||||
if [[ "$code" != "201" && "$code" != "200" ]]; then
|
||||
echo "error: upload of $(basename "$f") failed with HTTP $code" >&2
|
||||
cat /tmp/release-upload.json >&2 || true
|
||||
echo "" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Verify the release actually carries the artifacts we just sent.
|
||||
have="$(curl -sS "${AUTH[@]}" "$API/$RELEASE_ID" | python3 -c "
|
||||
import sys, json
|
||||
try:
|
||||
d = json.load(sys.stdin)
|
||||
except Exception:
|
||||
print(0); raise SystemExit
|
||||
print(len(d.get('assets', [])))" 2>/dev/null || echo 0)"
|
||||
if [[ "${have:-0}" -lt "${#all_artifacts[@]}" ]]; then
|
||||
echo "error: release has $have assets, expected ${#all_artifacts[@]}" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Verified $have artifacts on the release"
|
||||
|
||||
echo ""
|
||||
echo "Release live: $HOST/$REPO/releases/tag/$TAG"
|
||||
Reference in new issue
Block a user