Skip to content

Stop the state pull from swallowing its own failure - #33

Merged
Cam8863 merged 1 commit into
dependabot/github_actions/actions-39df277632from
fix/publish-state-pull
Aug 27, 2026
Merged

Cam8863 merged 1 commit into
dependabot/github_actions/actions-39df277632from
fix/publish-state-pull

Conversation

@guys-inc-ops

@guys-inc-ops guys-inc-ops Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Stack 2 of 2 — merge #24 first

linux ← #24 ← this PR

Based on #24's branch because both edit publish-apt.yml. Merging #24 first
auto-retargets this to linux.

The bug

aws s3 sync "s3://$BUCKET/$PREFIX" repo --endpoint-url "…" || true

A failed pull is indistinguishable from an empty repository. reprepro then adds
the one incoming package, exports, and the sync overwrites dists/ with a
single-package index
. Every previously published version silently stops being
listed. The pool objects survive but unreferenced, and the run is green.

This is the exact failure recorded in archivist's ADR 0001 as the reason that
tool regenerates from scratch instead of pulling mutable state. It was still
live here.

Harmless today with one release. It becomes a silent outage the moment there
are two, and nothing surfaces it until a user reports a missing version.

The fix

Let a real failure fail. || true was never needed for the first-publish
case — aws s3 sync from an absent prefix already exits 0.

And check completeness, not just exit status. A zero exit cannot prove the
pull was complete, so the step compares the remote object count with what
landed and refuses to continue if the remote has content and nothing arrived:

remote objects: 14, pulled: 0
::error::Remote holds 14 objects but none were pulled. Refusing to
::error::republish, which would drop every existing package from the index.

The step ended in '|| true', so a failed pull was indistinguishable from an
empty repository: reprepro would add the single incoming package, export, and
the sync would overwrite dists/ with a one-package index. Every previously
published version stops being listed, the pool objects survive unreferenced,
and the run stays green.

This is the failure mode recorded in archivist's ADR 0001 as the reason that
tool regenerates from scratch rather than pulling mutable state. It was still
live here.

Two changes. A genuine failure now fails the job, since there is no longer a
reason to suppress it - 'aws s3 sync' from an absent prefix already exits 0, so
the first publish into a new prefix was never the problem '|| true' solved.
And because a zero exit code alone cannot prove the pull was complete, the step
now compares the remote object count against what actually landed, and refuses
to continue if the remote has content and nothing arrived.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015AH1v3tR8Xw2DmKqJSipPd
@guys-inc-ops
guys-inc-ops Bot requested a review from Cam8863 as a code owner August 27, 2026 03:54
auto-merge was automatically disabled August 27, 2026 04:05

Pull Request is not mergeable

auto-merge was automatically disabled August 27, 2026 04:07

Pull Request is not mergeable

@Cam8863
Cam8863 merged commit 7ac9b7e into dependabot/github_actions/actions-39df277632 Aug 27, 2026
@Cam8863
Cam8863 deleted the fix/publish-state-pull branch August 27, 2026 04:07
Cam8863 pushed a commit that referenced this pull request Aug 27, 2026
* ci: bump the actions group across 1 directory with 8 updates

Bumps the actions group with 8 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [actions/checkout](https://github.com/actions/checkout) | `4` | `7` |
| [actions/upload-artifact](https://github.com/actions/upload-artifact) | `4` | `7` |
| [actions/setup-node](https://github.com/actions/setup-node) | `4` | `7` |
| [actions/download-artifact](https://github.com/actions/download-artifact) | `4` | `8` |
| [softprops/action-gh-release](https://github.com/softprops/action-gh-release) | `2` | `3` |
| [actions/setup-python](https://github.com/actions/setup-python) | `5` | `7` |
| [actions/github-script](https://github.com/actions/github-script) | `7` | `9` |
| [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) | `7.0.6` | `8.1.1` |



Updates `actions/checkout` from 4 to 7
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v4...v7)

Updates `actions/upload-artifact` from 4 to 7
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v4...v7)

Updates `actions/setup-node` from 4 to 7
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](actions/setup-node@v4...v7)

Updates `actions/download-artifact` from 4 to 8
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](actions/download-artifact@v4...v8)

Updates `softprops/action-gh-release` from 2 to 3
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](softprops/action-gh-release@v2...v3)

Updates `actions/setup-python` from 5 to 7
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](actions/setup-python@v5...v7)

Updates `actions/github-script` from 7 to 9
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](actions/github-script@v7...v9)

Updates `peter-evans/create-pull-request` from 7.0.6 to 8.1.1
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](peter-evans/create-pull-request@v7.0.6...v8.1.1)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/download-artifact
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/github-script
  dependency-version: '9'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/setup-node
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/setup-python
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: peter-evans/create-pull-request
  dependency-version: 8.1.1
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: softprops/action-gh-release
  dependency-version: '3'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>

* Stop the state pull from swallowing its own failure (#33)

The step ended in '|| true', so a failed pull was indistinguishable from an
empty repository: reprepro would add the single incoming package, export, and
the sync would overwrite dists/ with a one-package index. Every previously
published version stops being listed, the pool objects survive unreferenced,
and the run stays green.

This is the failure mode recorded in archivist's ADR 0001 as the reason that
tool regenerates from scratch rather than pulling mutable state. It was still
live here.

Two changes. A genuine failure now fails the job, since there is no longer a
reason to suppress it - 'aws s3 sync' from an absent prefix already exits 0, so
the first publish into a new prefix was never the problem '|| true' solved.
And because a zero exit code alone cannot prove the pull was complete, the step
now compares the remote object count against what actually landed, and refuses
to continue if the remote has content and nothing arrived.


Claude-Session: https://claude.ai/code/session_015AH1v3tR8Xw2DmKqJSipPd

Co-authored-by: guys-inc-ops[bot] <321481384+guys-inc-ops[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: guys-inc-ops[bot] <321481384+guys-inc-ops[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant