Tag every published per-arch image with an immutable per-release snapshot - #41

Merged
fnando merged 6 commits into
mainfrom
immutable-iteration-tags
Aug 26, 2026
Merged

Tag every published per-arch image with an immutable per-release snapshot#41
fnando merged 6 commits into
mainfrom
immutable-iteration-tags

Conversation

@fnando

Copy link
Copy Markdown
Member

Fixes#38.

What

Adds an immutable per-release snapshot tag for every published per-arch image: :‹cli›-rust‹key›-‹arch›-‹N› (e.g. 27.0.0-rust1.95.0-slim-trixie-amd64-0), minted by the publish workflow for each (rust base, arch) a release builds. Also adds a manually-dispatched backfill workflow to reconstruct these tags for already-published releases, recovering each per-arch digest from the release's prov-*.intoto.jsonl attestation assets.

Why

SEP-58 verifiable builds pin per-arch content digests (bldimg) into deployed contracts permanently. Today those digests are only reachable through mutable tags (:‹cli›-rust‹key›-‹arch›, :‹cli›, :latest), which re-point on the next publish — orphaning the old digest and making it garbage-collectable. The immutable per-arch tags keep every published digest referenced by a tag that never moves, so none can be garbage-collected. Coverage is per-arch across every rust pair a release built, not just the default one (e.g. v27.0.0 shipped four rust pairs).

CopilotAI balanced review requested due to automatic review settings August 20, 2026 00:00
@fnando

Copy link
Copy Markdown
MemberAuthor

Tested and confirmed end-to-end against the experimental fork: the publish flow and the backfill workflow both produced the immutable per-arch snapshot tags as expected.

@fnandofnando self-assigned this Aug 20, 2026
@fnandofnando added this to DevXAug 20, 2026
@github-project-automationgithub-project-automationBot moved this to Backlog (Not Ready) in DevXAug 20, 2026
@fnandofnando moved this from Backlog (Not Ready) to Needs Review in DevXAug 20, 2026
@fnando
fnando requested review from a team and leighmccullochAugust 20, 2026 00:04

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds immutable, per-release architecture tags to preserve SEP-58 image digests, plus tooling to backfill historical releases.

Changes:

  • Introduces uniform release iteration tags beginning at -0.
  • Publishes per-architecture snapshot tags and documents them.
  • Adds a provenance-based backfill workflow and tests.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
.github/workflows/backfill.ymlAdds manual backfill workflow.
.github/workflows/publish.ymlPropagates iteration into publishing.
RELEASE.mdDocuments snapshots and backfilling.
docker/README.mdDocuments mutable and immutable tags.
scripts/backfill_iteration_tags.pyReconstructs historical snapshot tags.
scripts/lib/gh_cli.pyAdds branch, file, and asset helpers.
scripts/publish_aliases.pyClarifies moving-alias behavior.
scripts/publish_manifests.pyCreates per-architecture snapshot tags.
scripts/release_body.pyLists snapshots in release bodies.
scripts/release_pr_body.pyHandles iteration-zero releases.
scripts/release_prepare.pySelects iteration tags using releases and branches.
tests/integration/test_release_prepare.pyTests iteration selection.
tests/unit/test_backfill_iteration_tags.pyTests backfill behavior.
tests/unit/test_publish_aliases.pyVerifies aliases exclude snapshots.
tests/unit/test_publish_manifests.pyTests snapshot publication.
tests/unit/test_release_body.pyTests snapshot release documentation.
tests/unit/test_release_pr_body.pyTests iteration-zero PR content.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadscripts/lib/gh_cli.py
Comment threadscripts/publish_manifests.py Outdated
Comment threadscripts/backfill_iteration_tags.py Outdated
@fnando
fnandoforce-pushed the immutable-iteration-tags branch from 694f928 to e839478CompareAugust 21, 2026 13:42
@fnando
fnandoforce-pushed the immutable-iteration-tags branch from e839478 to 31092eeCompareAugust 21, 2026 13:43

@leighmccullochleighmcculloch left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple comments, otherwise lgtm.

Comment threadscripts/backfill_iteration_tags.py Outdated
Comment threadscripts/publish_manifests.py Outdated
@fnando
fnando enabled auto-merge (squash) August 26, 2026 13:48
@fnando
fnando merged commit 332b6b4 into mainAug 26, 2026
12 checks passed
@fnando
fnando deleted the immutable-iteration-tags branch August 26, 2026 14:01
@github-project-automationgithub-project-automationBot moved this from Needs Review to Done in DevXAug 26, 2026
Comment threadscripts/lib/gh_cli.py
def list_release_branch_tags(repo: str) -> list[str]:
"""Release tags of the `release/<tag>` branches that exist on the repo.

A release branch is created at prepare time and persists across the

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we use 'delete branch on merge' on most repos, and so GitHub will auto delete the release branch, is that an issue?

cli = args.stellar_cli_version
registry = args.registry

iteration = latest_iteration(gh_cli.list_release_tags(args.repo), cli)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If v25.2.0 and v25.2.0-1 both exist as GitHub Releases, but v25.2.0-1's publish run fails before the build/push step, will backfill work as expected? Or will a next run get stuck?

Comment threadRELEASE.md
Moving aliases (`:<cli>`, `:latest`) re-point each release.
Moving aliases (`:<cli>`, `:latest`) re-point each release. The immutable `:<cli>-rust<key>-<arch>-<N>` snapshots are the exception — they're keyed by the release's refresh index, so a re-run recreates the same tags at the same digests rather than moving them.

To recover from a failed run, use **Re-run failed jobs** from the GitHub Actions UI; re-runs simply rebuild and overwrite. Recovering from a corrupt push is the same — just re-run, no manual tag deletion needed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think some of the text here needs updating. Are the statements about rerunning still correct? Won't that result in new releases now? Could it get stuck trying to republish an existing?

# auto-picked by the release workflow. Strip leading "v" and the
# trailing "-<N>" to derive the stellar-cli version; the refresh
# index N (0 when there's no suffix, i.e. the first release) names
# the immutable :<version>-<N> Docker tag published by the aliases

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is :<version>-<N> still exist, or the tag is :<cli>-rust<key>-<arch>-<N> now?

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Re-publishing version tags orphans previously published digests — which SEP-58 bldimg pins on chain permanently

3 participants

@fnando@leighmcculloch
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks"); } } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); } })(); (function(){ try { var __m = "github.com"; var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Tag every published per-arch image with an immutable per-release snapshot - #41

Merged
fnando merged 6 commits into
mainfrom
immutable-iteration-tags
Aug 26, 2026
Merged

Tag every published per-arch image with an immutable per-release snapshot#41
fnando merged 6 commits into
mainfrom
immutable-iteration-tags

Conversation

@fnando

Copy link
Copy Markdown
Member

Fixes#38.

What

Adds an immutable per-release snapshot tag for every published per-arch image: :‹cli›-rust‹key›-‹arch›-‹N› (e.g. 27.0.0-rust1.95.0-slim-trixie-amd64-0), minted by the publish workflow for each (rust base, arch) a release builds. Also adds a manually-dispatched backfill workflow to reconstruct these tags for already-published releases, recovering each per-arch digest from the release's prov-*.intoto.jsonl attestation assets.

Why

SEP-58 verifiable builds pin per-arch content digests (bldimg) into deployed contracts permanently. Today those digests are only reachable through mutable tags (:‹cli›-rust‹key›-‹arch›, :‹cli›, :latest), which re-point on the next publish — orphaning the old digest and making it garbage-collectable. The immutable per-arch tags keep every published digest referenced by a tag that never moves, so none can be garbage-collected. Coverage is per-arch across every rust pair a release built, not just the default one (e.g. v27.0.0 shipped four rust pairs).

CopilotAI balanced review requested due to automatic review settings August 20, 2026 00:00
@fnando

Copy link
Copy Markdown
MemberAuthor

Tested and confirmed end-to-end against the experimental fork: the publish flow and the backfill workflow both produced the immutable per-arch snapshot tags as expected.

@fnandofnando self-assigned this Aug 20, 2026
@fnandofnando added this to DevXAug 20, 2026
@github-project-automationgithub-project-automationBot moved this to Backlog (Not Ready) in DevXAug 20, 2026
@fnandofnando moved this from Backlog (Not Ready) to Needs Review in DevXAug 20, 2026
@fnando
fnando requested review from a team and leighmccullochAugust 20, 2026 00:04

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds immutable, per-release architecture tags to preserve SEP-58 image digests, plus tooling to backfill historical releases.

Changes:

  • Introduces uniform release iteration tags beginning at -0.
  • Publishes per-architecture snapshot tags and documents them.
  • Adds a provenance-based backfill workflow and tests.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
.github/workflows/backfill.ymlAdds manual backfill workflow.
.github/workflows/publish.ymlPropagates iteration into publishing.
RELEASE.mdDocuments snapshots and backfilling.
docker/README.mdDocuments mutable and immutable tags.
scripts/backfill_iteration_tags.pyReconstructs historical snapshot tags.
scripts/lib/gh_cli.pyAdds branch, file, and asset helpers.
scripts/publish_aliases.pyClarifies moving-alias behavior.
scripts/publish_manifests.pyCreates per-architecture snapshot tags.
scripts/release_body.pyLists snapshots in release bodies.
scripts/release_pr_body.pyHandles iteration-zero releases.
scripts/release_prepare.pySelects iteration tags using releases and branches.
tests/integration/test_release_prepare.pyTests iteration selection.
tests/unit/test_backfill_iteration_tags.pyTests backfill behavior.
tests/unit/test_publish_aliases.pyVerifies aliases exclude snapshots.
tests/unit/test_publish_manifests.pyTests snapshot publication.
tests/unit/test_release_body.pyTests snapshot release documentation.
tests/unit/test_release_pr_body.pyTests iteration-zero PR content.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadscripts/lib/gh_cli.py
Comment threadscripts/publish_manifests.py Outdated
Comment threadscripts/backfill_iteration_tags.py Outdated
@fnando
fnandoforce-pushed the immutable-iteration-tags branch from 694f928 to e839478CompareAugust 21, 2026 13:42
@fnando
fnandoforce-pushed the immutable-iteration-tags branch from e839478 to 31092eeCompareAugust 21, 2026 13:43

@leighmccullochleighmcculloch left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple comments, otherwise lgtm.

Comment threadscripts/backfill_iteration_tags.py Outdated
Comment threadscripts/publish_manifests.py Outdated
@fnando
fnando enabled auto-merge (squash) August 26, 2026 13:48
@fnando
fnando merged commit 332b6b4 into mainAug 26, 2026
12 checks passed
@fnando
fnando deleted the immutable-iteration-tags branch August 26, 2026 14:01
@github-project-automationgithub-project-automationBot moved this from Needs Review to Done in DevXAug 26, 2026
Comment threadscripts/lib/gh_cli.py
def list_release_branch_tags(repo: str) -> list[str]:
"""Release tags of the `release/<tag>` branches that exist on the repo.

A release branch is created at prepare time and persists across the

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we use 'delete branch on merge' on most repos, and so GitHub will auto delete the release branch, is that an issue?

cli = args.stellar_cli_version
registry = args.registry

iteration = latest_iteration(gh_cli.list_release_tags(args.repo), cli)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If v25.2.0 and v25.2.0-1 both exist as GitHub Releases, but v25.2.0-1's publish run fails before the build/push step, will backfill work as expected? Or will a next run get stuck?

Comment threadRELEASE.md
Moving aliases (`:<cli>`, `:latest`) re-point each release.
Moving aliases (`:<cli>`, `:latest`) re-point each release. The immutable `:<cli>-rust<key>-<arch>-<N>` snapshots are the exception — they're keyed by the release's refresh index, so a re-run recreates the same tags at the same digests rather than moving them.

To recover from a failed run, use **Re-run failed jobs** from the GitHub Actions UI; re-runs simply rebuild and overwrite. Recovering from a corrupt push is the same — just re-run, no manual tag deletion needed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think some of the text here needs updating. Are the statements about rerunning still correct? Won't that result in new releases now? Could it get stuck trying to republish an existing?

# auto-picked by the release workflow. Strip leading "v" and the
# trailing "-<N>" to derive the stellar-cli version; the refresh
# index N (0 when there's no suffix, i.e. the first release) names
# the immutable :<version>-<N> Docker tag published by the aliases

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is :<version>-<N> still exist, or the tag is :<cli>-rust<key>-<arch>-<N> now?

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Re-publishing version tags orphans previously published digests — which SEP-58 bldimg pins on chain permanently

3 participants

@fnando@leighmcculloch
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Tag every published per-arch image with an immutable per-release snapshot - #41

Merged
fnando merged 6 commits into
mainfrom
immutable-iteration-tags
Aug 26, 2026
Merged

Tag every published per-arch image with an immutable per-release snapshot#41
fnando merged 6 commits into
mainfrom
immutable-iteration-tags

Conversation

@fnando

Copy link
Copy Markdown
Member

Fixes#38.

What

Adds an immutable per-release snapshot tag for every published per-arch image: :‹cli›-rust‹key›-‹arch›-‹N› (e.g. 27.0.0-rust1.95.0-slim-trixie-amd64-0), minted by the publish workflow for each (rust base, arch) a release builds. Also adds a manually-dispatched backfill workflow to reconstruct these tags for already-published releases, recovering each per-arch digest from the release's prov-*.intoto.jsonl attestation assets.

Why

SEP-58 verifiable builds pin per-arch content digests (bldimg) into deployed contracts permanently. Today those digests are only reachable through mutable tags (:‹cli›-rust‹key›-‹arch›, :‹cli›, :latest), which re-point on the next publish — orphaning the old digest and making it garbage-collectable. The immutable per-arch tags keep every published digest referenced by a tag that never moves, so none can be garbage-collected. Coverage is per-arch across every rust pair a release built, not just the default one (e.g. v27.0.0 shipped four rust pairs).

CopilotAI balanced review requested due to automatic review settings August 20, 2026 00:00
@fnando

Copy link
Copy Markdown
MemberAuthor

Tested and confirmed end-to-end against the experimental fork: the publish flow and the backfill workflow both produced the immutable per-arch snapshot tags as expected.

@fnandofnando self-assigned this Aug 20, 2026
@fnandofnando added this to DevXAug 20, 2026
@github-project-automationgithub-project-automationBot moved this to Backlog (Not Ready) in DevXAug 20, 2026
@fnandofnando moved this from Backlog (Not Ready) to Needs Review in DevXAug 20, 2026
@fnando
fnando requested review from a team and leighmccullochAugust 20, 2026 00:04

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds immutable, per-release architecture tags to preserve SEP-58 image digests, plus tooling to backfill historical releases.

Changes:

  • Introduces uniform release iteration tags beginning at -0.
  • Publishes per-architecture snapshot tags and documents them.
  • Adds a provenance-based backfill workflow and tests.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
.github/workflows/backfill.ymlAdds manual backfill workflow.
.github/workflows/publish.ymlPropagates iteration into publishing.
RELEASE.mdDocuments snapshots and backfilling.
docker/README.mdDocuments mutable and immutable tags.
scripts/backfill_iteration_tags.pyReconstructs historical snapshot tags.
scripts/lib/gh_cli.pyAdds branch, file, and asset helpers.
scripts/publish_aliases.pyClarifies moving-alias behavior.
scripts/publish_manifests.pyCreates per-architecture snapshot tags.
scripts/release_body.pyLists snapshots in release bodies.
scripts/release_pr_body.pyHandles iteration-zero releases.
scripts/release_prepare.pySelects iteration tags using releases and branches.
tests/integration/test_release_prepare.pyTests iteration selection.
tests/unit/test_backfill_iteration_tags.pyTests backfill behavior.
tests/unit/test_publish_aliases.pyVerifies aliases exclude snapshots.
tests/unit/test_publish_manifests.pyTests snapshot publication.
tests/unit/test_release_body.pyTests snapshot release documentation.
tests/unit/test_release_pr_body.pyTests iteration-zero PR content.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadscripts/lib/gh_cli.py
Comment threadscripts/publish_manifests.py Outdated
Comment threadscripts/backfill_iteration_tags.py Outdated
@fnando
fnandoforce-pushed the immutable-iteration-tags branch from 694f928 to e839478CompareAugust 21, 2026 13:42
@fnando
fnandoforce-pushed the immutable-iteration-tags branch from e839478 to 31092eeCompareAugust 21, 2026 13:43

@leighmccullochleighmcculloch left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple comments, otherwise lgtm.

Comment threadscripts/backfill_iteration_tags.py Outdated
Comment threadscripts/publish_manifests.py Outdated
@fnando
fnando enabled auto-merge (squash) August 26, 2026 13:48
@fnando
fnando merged commit 332b6b4 into mainAug 26, 2026
12 checks passed
@fnando
fnando deleted the immutable-iteration-tags branch August 26, 2026 14:01
@github-project-automationgithub-project-automationBot moved this from Needs Review to Done in DevXAug 26, 2026
Comment threadscripts/lib/gh_cli.py
def list_release_branch_tags(repo: str) -> list[str]:
"""Release tags of the `release/<tag>` branches that exist on the repo.

A release branch is created at prepare time and persists across the

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we use 'delete branch on merge' on most repos, and so GitHub will auto delete the release branch, is that an issue?

cli = args.stellar_cli_version
registry = args.registry

iteration = latest_iteration(gh_cli.list_release_tags(args.repo), cli)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If v25.2.0 and v25.2.0-1 both exist as GitHub Releases, but v25.2.0-1's publish run fails before the build/push step, will backfill work as expected? Or will a next run get stuck?

Comment threadRELEASE.md
Moving aliases (`:<cli>`, `:latest`) re-point each release.
Moving aliases (`:<cli>`, `:latest`) re-point each release. The immutable `:<cli>-rust<key>-<arch>-<N>` snapshots are the exception — they're keyed by the release's refresh index, so a re-run recreates the same tags at the same digests rather than moving them.

To recover from a failed run, use **Re-run failed jobs** from the GitHub Actions UI; re-runs simply rebuild and overwrite. Recovering from a corrupt push is the same — just re-run, no manual tag deletion needed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think some of the text here needs updating. Are the statements about rerunning still correct? Won't that result in new releases now? Could it get stuck trying to republish an existing?

# auto-picked by the release workflow. Strip leading "v" and the
# trailing "-<N>" to derive the stellar-cli version; the refresh
# index N (0 when there's no suffix, i.e. the first release) names
# the immutable :<version>-<N> Docker tag published by the aliases

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is :<version>-<N> still exist, or the tag is :<cli>-rust<key>-<arch>-<N> now?

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Re-publishing version tags orphans previously published digests — which SEP-58 bldimg pins on chain permanently

3 participants

@fnando@leighmcculloch
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length \u003e 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Tag every published per-arch image with an immutable per-release snapshot - #41

Merged
fnando merged 6 commits into
mainfrom
immutable-iteration-tags
Aug 26, 2026
Merged

Tag every published per-arch image with an immutable per-release snapshot#41
fnando merged 6 commits into
mainfrom
immutable-iteration-tags

Conversation

@fnando

Copy link
Copy Markdown
Member

Fixes#38.

What

Adds an immutable per-release snapshot tag for every published per-arch image: :‹cli›-rust‹key›-‹arch›-‹N› (e.g. 27.0.0-rust1.95.0-slim-trixie-amd64-0), minted by the publish workflow for each (rust base, arch) a release builds. Also adds a manually-dispatched backfill workflow to reconstruct these tags for already-published releases, recovering each per-arch digest from the release's prov-*.intoto.jsonl attestation assets.

Why

SEP-58 verifiable builds pin per-arch content digests (bldimg) into deployed contracts permanently. Today those digests are only reachable through mutable tags (:‹cli›-rust‹key›-‹arch›, :‹cli›, :latest), which re-point on the next publish — orphaning the old digest and making it garbage-collectable. The immutable per-arch tags keep every published digest referenced by a tag that never moves, so none can be garbage-collected. Coverage is per-arch across every rust pair a release built, not just the default one (e.g. v27.0.0 shipped four rust pairs).

CopilotAI balanced review requested due to automatic review settings August 20, 2026 00:00
@fnando

Copy link
Copy Markdown
MemberAuthor

Tested and confirmed end-to-end against the experimental fork: the publish flow and the backfill workflow both produced the immutable per-arch snapshot tags as expected.

@fnandofnando self-assigned this Aug 20, 2026
@fnandofnando added this to DevXAug 20, 2026
@github-project-automationgithub-project-automationBot moved this to Backlog (Not Ready) in DevXAug 20, 2026
@fnandofnando moved this from Backlog (Not Ready) to Needs Review in DevXAug 20, 2026
@fnando
fnando requested review from a team and leighmccullochAugust 20, 2026 00:04

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds immutable, per-release architecture tags to preserve SEP-58 image digests, plus tooling to backfill historical releases.

Changes:

  • Introduces uniform release iteration tags beginning at -0.
  • Publishes per-architecture snapshot tags and documents them.
  • Adds a provenance-based backfill workflow and tests.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
.github/workflows/backfill.ymlAdds manual backfill workflow.
.github/workflows/publish.ymlPropagates iteration into publishing.
RELEASE.mdDocuments snapshots and backfilling.
docker/README.mdDocuments mutable and immutable tags.
scripts/backfill_iteration_tags.pyReconstructs historical snapshot tags.
scripts/lib/gh_cli.pyAdds branch, file, and asset helpers.
scripts/publish_aliases.pyClarifies moving-alias behavior.
scripts/publish_manifests.pyCreates per-architecture snapshot tags.
scripts/release_body.pyLists snapshots in release bodies.
scripts/release_pr_body.pyHandles iteration-zero releases.
scripts/release_prepare.pySelects iteration tags using releases and branches.
tests/integration/test_release_prepare.pyTests iteration selection.
tests/unit/test_backfill_iteration_tags.pyTests backfill behavior.
tests/unit/test_publish_aliases.pyVerifies aliases exclude snapshots.
tests/unit/test_publish_manifests.pyTests snapshot publication.
tests/unit/test_release_body.pyTests snapshot release documentation.
tests/unit/test_release_pr_body.pyTests iteration-zero PR content.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadscripts/lib/gh_cli.py
Comment threadscripts/publish_manifests.py Outdated
Comment threadscripts/backfill_iteration_tags.py Outdated
@fnando
fnandoforce-pushed the immutable-iteration-tags branch from 694f928 to e839478CompareAugust 21, 2026 13:42
@fnando
fnandoforce-pushed the immutable-iteration-tags branch from e839478 to 31092eeCompareAugust 21, 2026 13:43

@leighmccullochleighmcculloch left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple comments, otherwise lgtm.

Comment threadscripts/backfill_iteration_tags.py Outdated
Comment threadscripts/publish_manifests.py Outdated
@fnando
fnando enabled auto-merge (squash) August 26, 2026 13:48
@fnando
fnando merged commit 332b6b4 into mainAug 26, 2026
12 checks passed
@fnando
fnando deleted the immutable-iteration-tags branch August 26, 2026 14:01
@github-project-automationgithub-project-automationBot moved this from Needs Review to Done in DevXAug 26, 2026
Comment threadscripts/lib/gh_cli.py
def list_release_branch_tags(repo: str) -> list[str]:
"""Release tags of the `release/<tag>` branches that exist on the repo.

A release branch is created at prepare time and persists across the

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we use 'delete branch on merge' on most repos, and so GitHub will auto delete the release branch, is that an issue?

cli = args.stellar_cli_version
registry = args.registry

iteration = latest_iteration(gh_cli.list_release_tags(args.repo), cli)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If v25.2.0 and v25.2.0-1 both exist as GitHub Releases, but v25.2.0-1's publish run fails before the build/push step, will backfill work as expected? Or will a next run get stuck?

Comment threadRELEASE.md
Moving aliases (`:<cli>`, `:latest`) re-point each release.
Moving aliases (`:<cli>`, `:latest`) re-point each release. The immutable `:<cli>-rust<key>-<arch>-<N>` snapshots are the exception — they're keyed by the release's refresh index, so a re-run recreates the same tags at the same digests rather than moving them.

To recover from a failed run, use **Re-run failed jobs** from the GitHub Actions UI; re-runs simply rebuild and overwrite. Recovering from a corrupt push is the same — just re-run, no manual tag deletion needed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think some of the text here needs updating. Are the statements about rerunning still correct? Won't that result in new releases now? Could it get stuck trying to republish an existing?

# auto-picked by the release workflow. Strip leading "v" and the
# trailing "-<N>" to derive the stellar-cli version; the refresh
# index N (0 when there's no suffix, i.e. the first release) names
# the immutable :<version>-<N> Docker tag published by the aliases

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is :<version>-<N> still exist, or the tag is :<cli>-rust<key>-<arch>-<N> now?

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Re-publishing version tags orphans previously published digests — which SEP-58 bldimg pins on chain permanently

3 participants

@fnando@leighmcculloch
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Tag every published per-arch image with an immutable per-release snapshot - #41

Merged
fnando merged 6 commits into
mainfrom
immutable-iteration-tags
Aug 26, 2026
Merged

Tag every published per-arch image with an immutable per-release snapshot#41
fnando merged 6 commits into
mainfrom
immutable-iteration-tags

Conversation

@fnando

Copy link
Copy Markdown
Member

Fixes#38.

What

Adds an immutable per-release snapshot tag for every published per-arch image: :‹cli›-rust‹key›-‹arch›-‹N› (e.g. 27.0.0-rust1.95.0-slim-trixie-amd64-0), minted by the publish workflow for each (rust base, arch) a release builds. Also adds a manually-dispatched backfill workflow to reconstruct these tags for already-published releases, recovering each per-arch digest from the release's prov-*.intoto.jsonl attestation assets.

Why

SEP-58 verifiable builds pin per-arch content digests (bldimg) into deployed contracts permanently. Today those digests are only reachable through mutable tags (:‹cli›-rust‹key›-‹arch›, :‹cli›, :latest), which re-point on the next publish — orphaning the old digest and making it garbage-collectable. The immutable per-arch tags keep every published digest referenced by a tag that never moves, so none can be garbage-collected. Coverage is per-arch across every rust pair a release built, not just the default one (e.g. v27.0.0 shipped four rust pairs).

CopilotAI balanced review requested due to automatic review settings August 20, 2026 00:00
@fnando

Copy link
Copy Markdown
MemberAuthor

Tested and confirmed end-to-end against the experimental fork: the publish flow and the backfill workflow both produced the immutable per-arch snapshot tags as expected.

@fnandofnando self-assigned this Aug 20, 2026
@fnandofnando added this to DevXAug 20, 2026
@github-project-automationgithub-project-automationBot moved this to Backlog (Not Ready) in DevXAug 20, 2026
@fnandofnando moved this from Backlog (Not Ready) to Needs Review in DevXAug 20, 2026
@fnando
fnando requested review from a team and leighmccullochAugust 20, 2026 00:04

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds immutable, per-release architecture tags to preserve SEP-58 image digests, plus tooling to backfill historical releases.

Changes:

  • Introduces uniform release iteration tags beginning at -0.
  • Publishes per-architecture snapshot tags and documents them.
  • Adds a provenance-based backfill workflow and tests.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
.github/workflows/backfill.ymlAdds manual backfill workflow.
.github/workflows/publish.ymlPropagates iteration into publishing.
RELEASE.mdDocuments snapshots and backfilling.
docker/README.mdDocuments mutable and immutable tags.
scripts/backfill_iteration_tags.pyReconstructs historical snapshot tags.
scripts/lib/gh_cli.pyAdds branch, file, and asset helpers.
scripts/publish_aliases.pyClarifies moving-alias behavior.
scripts/publish_manifests.pyCreates per-architecture snapshot tags.
scripts/release_body.pyLists snapshots in release bodies.
scripts/release_pr_body.pyHandles iteration-zero releases.
scripts/release_prepare.pySelects iteration tags using releases and branches.
tests/integration/test_release_prepare.pyTests iteration selection.
tests/unit/test_backfill_iteration_tags.pyTests backfill behavior.
tests/unit/test_publish_aliases.pyVerifies aliases exclude snapshots.
tests/unit/test_publish_manifests.pyTests snapshot publication.
tests/unit/test_release_body.pyTests snapshot release documentation.
tests/unit/test_release_pr_body.pyTests iteration-zero PR content.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadscripts/lib/gh_cli.py
Comment threadscripts/publish_manifests.py Outdated
Comment threadscripts/backfill_iteration_tags.py Outdated
@fnando
fnandoforce-pushed the immutable-iteration-tags branch from 694f928 to e839478CompareAugust 21, 2026 13:42
@fnando
fnandoforce-pushed the immutable-iteration-tags branch from e839478 to 31092eeCompareAugust 21, 2026 13:43

@leighmccullochleighmcculloch left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple comments, otherwise lgtm.

Comment threadscripts/backfill_iteration_tags.py Outdated
Comment threadscripts/publish_manifests.py Outdated
@fnando
fnando enabled auto-merge (squash) August 26, 2026 13:48
@fnando
fnando merged commit 332b6b4 into mainAug 26, 2026
12 checks passed
@fnando
fnando deleted the immutable-iteration-tags branch August 26, 2026 14:01
@github-project-automationgithub-project-automationBot moved this from Needs Review to Done in DevXAug 26, 2026
Comment threadscripts/lib/gh_cli.py
def list_release_branch_tags(repo: str) -> list[str]:
"""Release tags of the `release/<tag>` branches that exist on the repo.

A release branch is created at prepare time and persists across the

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we use 'delete branch on merge' on most repos, and so GitHub will auto delete the release branch, is that an issue?

cli = args.stellar_cli_version
registry = args.registry

iteration = latest_iteration(gh_cli.list_release_tags(args.repo), cli)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If v25.2.0 and v25.2.0-1 both exist as GitHub Releases, but v25.2.0-1's publish run fails before the build/push step, will backfill work as expected? Or will a next run get stuck?

Comment threadRELEASE.md
Moving aliases (`:<cli>`, `:latest`) re-point each release.
Moving aliases (`:<cli>`, `:latest`) re-point each release. The immutable `:<cli>-rust<key>-<arch>-<N>` snapshots are the exception — they're keyed by the release's refresh index, so a re-run recreates the same tags at the same digests rather than moving them.

To recover from a failed run, use **Re-run failed jobs** from the GitHub Actions UI; re-runs simply rebuild and overwrite. Recovering from a corrupt push is the same — just re-run, no manual tag deletion needed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think some of the text here needs updating. Are the statements about rerunning still correct? Won't that result in new releases now? Could it get stuck trying to republish an existing?

# auto-picked by the release workflow. Strip leading "v" and the
# trailing "-<N>" to derive the stellar-cli version; the refresh
# index N (0 when there's no suffix, i.e. the first release) names
# the immutable :<version>-<N> Docker tag published by the aliases

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is :<version>-<N> still exist, or the tag is :<cli>-rust<key>-<arch>-<N> now?

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Re-publishing version tags orphans previously published digests — which SEP-58 bldimg pins on chain permanently

3 participants

@fnando@leighmcculloch
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Tag every published per-arch image with an immutable per-release snapshot - #41

Merged
fnando merged 6 commits into
mainfrom
immutable-iteration-tags
Aug 26, 2026
Merged

Tag every published per-arch image with an immutable per-release snapshot#41
fnando merged 6 commits into
mainfrom
immutable-iteration-tags

Conversation

@fnando

Copy link
Copy Markdown
Member

Fixes#38.

What

Adds an immutable per-release snapshot tag for every published per-arch image: :‹cli›-rust‹key›-‹arch›-‹N› (e.g. 27.0.0-rust1.95.0-slim-trixie-amd64-0), minted by the publish workflow for each (rust base, arch) a release builds. Also adds a manually-dispatched backfill workflow to reconstruct these tags for already-published releases, recovering each per-arch digest from the release's prov-*.intoto.jsonl attestation assets.

Why

SEP-58 verifiable builds pin per-arch content digests (bldimg) into deployed contracts permanently. Today those digests are only reachable through mutable tags (:‹cli›-rust‹key›-‹arch›, :‹cli›, :latest), which re-point on the next publish — orphaning the old digest and making it garbage-collectable. The immutable per-arch tags keep every published digest referenced by a tag that never moves, so none can be garbage-collected. Coverage is per-arch across every rust pair a release built, not just the default one (e.g. v27.0.0 shipped four rust pairs).

CopilotAI balanced review requested due to automatic review settings August 20, 2026 00:00
@fnando

Copy link
Copy Markdown
MemberAuthor

Tested and confirmed end-to-end against the experimental fork: the publish flow and the backfill workflow both produced the immutable per-arch snapshot tags as expected.

@fnandofnando self-assigned this Aug 20, 2026
@fnandofnando added this to DevXAug 20, 2026
@github-project-automationgithub-project-automationBot moved this to Backlog (Not Ready) in DevXAug 20, 2026
@fnandofnando moved this from Backlog (Not Ready) to Needs Review in DevXAug 20, 2026
@fnando
fnando requested review from a team and leighmccullochAugust 20, 2026 00:04

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds immutable, per-release architecture tags to preserve SEP-58 image digests, plus tooling to backfill historical releases.

Changes:

  • Introduces uniform release iteration tags beginning at -0.
  • Publishes per-architecture snapshot tags and documents them.
  • Adds a provenance-based backfill workflow and tests.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
.github/workflows/backfill.ymlAdds manual backfill workflow.
.github/workflows/publish.ymlPropagates iteration into publishing.
RELEASE.mdDocuments snapshots and backfilling.
docker/README.mdDocuments mutable and immutable tags.
scripts/backfill_iteration_tags.pyReconstructs historical snapshot tags.
scripts/lib/gh_cli.pyAdds branch, file, and asset helpers.
scripts/publish_aliases.pyClarifies moving-alias behavior.
scripts/publish_manifests.pyCreates per-architecture snapshot tags.
scripts/release_body.pyLists snapshots in release bodies.
scripts/release_pr_body.pyHandles iteration-zero releases.
scripts/release_prepare.pySelects iteration tags using releases and branches.
tests/integration/test_release_prepare.pyTests iteration selection.
tests/unit/test_backfill_iteration_tags.pyTests backfill behavior.
tests/unit/test_publish_aliases.pyVerifies aliases exclude snapshots.
tests/unit/test_publish_manifests.pyTests snapshot publication.
tests/unit/test_release_body.pyTests snapshot release documentation.
tests/unit/test_release_pr_body.pyTests iteration-zero PR content.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadscripts/lib/gh_cli.py
Comment threadscripts/publish_manifests.py Outdated
Comment threadscripts/backfill_iteration_tags.py Outdated
@fnando
fnandoforce-pushed the immutable-iteration-tags branch from 694f928 to e839478CompareAugust 21, 2026 13:42
@fnando
fnandoforce-pushed the immutable-iteration-tags branch from e839478 to 31092eeCompareAugust 21, 2026 13:43

@leighmccullochleighmcculloch left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple comments, otherwise lgtm.

Comment threadscripts/backfill_iteration_tags.py Outdated
Comment threadscripts/publish_manifests.py Outdated
@fnando
fnando enabled auto-merge (squash) August 26, 2026 13:48
@fnando
fnando merged commit 332b6b4 into mainAug 26, 2026
12 checks passed
@fnando
fnando deleted the immutable-iteration-tags branch August 26, 2026 14:01
@github-project-automationgithub-project-automationBot moved this from Needs Review to Done in DevXAug 26, 2026
Comment threadscripts/lib/gh_cli.py
def list_release_branch_tags(repo: str) -> list[str]:
"""Release tags of the `release/<tag>` branches that exist on the repo.

A release branch is created at prepare time and persists across the

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we use 'delete branch on merge' on most repos, and so GitHub will auto delete the release branch, is that an issue?

cli = args.stellar_cli_version
registry = args.registry

iteration = latest_iteration(gh_cli.list_release_tags(args.repo), cli)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If v25.2.0 and v25.2.0-1 both exist as GitHub Releases, but v25.2.0-1's publish run fails before the build/push step, will backfill work as expected? Or will a next run get stuck?

Comment threadRELEASE.md
Moving aliases (`:<cli>`, `:latest`) re-point each release.
Moving aliases (`:<cli>`, `:latest`) re-point each release. The immutable `:<cli>-rust<key>-<arch>-<N>` snapshots are the exception — they're keyed by the release's refresh index, so a re-run recreates the same tags at the same digests rather than moving them.

To recover from a failed run, use **Re-run failed jobs** from the GitHub Actions UI; re-runs simply rebuild and overwrite. Recovering from a corrupt push is the same — just re-run, no manual tag deletion needed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think some of the text here needs updating. Are the statements about rerunning still correct? Won't that result in new releases now? Could it get stuck trying to republish an existing?

# auto-picked by the release workflow. Strip leading "v" and the
# trailing "-<N>" to derive the stellar-cli version; the refresh
# index N (0 when there's no suffix, i.e. the first release) names
# the immutable :<version>-<N> Docker tag published by the aliases

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is :<version>-<N> still exist, or the tag is :<cli>-rust<key>-<arch>-<N> now?

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Re-publishing version tags orphans previously published digests — which SEP-58 bldimg pins on chain permanently

3 participants

@fnando@leighmcculloch
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Tag every published per-arch image with an immutable per-release snapshot - #41

Merged
fnando merged 6 commits into
mainfrom
immutable-iteration-tags
Aug 26, 2026
Merged

Tag every published per-arch image with an immutable per-release snapshot#41
fnando merged 6 commits into
mainfrom
immutable-iteration-tags

Conversation

@fnando

Copy link
Copy Markdown
Member

Fixes#38.

What

Adds an immutable per-release snapshot tag for every published per-arch image: :‹cli›-rust‹key›-‹arch›-‹N› (e.g. 27.0.0-rust1.95.0-slim-trixie-amd64-0), minted by the publish workflow for each (rust base, arch) a release builds. Also adds a manually-dispatched backfill workflow to reconstruct these tags for already-published releases, recovering each per-arch digest from the release's prov-*.intoto.jsonl attestation assets.

Why

SEP-58 verifiable builds pin per-arch content digests (bldimg) into deployed contracts permanently. Today those digests are only reachable through mutable tags (:‹cli›-rust‹key›-‹arch›, :‹cli›, :latest), which re-point on the next publish — orphaning the old digest and making it garbage-collectable. The immutable per-arch tags keep every published digest referenced by a tag that never moves, so none can be garbage-collected. Coverage is per-arch across every rust pair a release built, not just the default one (e.g. v27.0.0 shipped four rust pairs).

CopilotAI balanced review requested due to automatic review settings August 20, 2026 00:00
@fnando

Copy link
Copy Markdown
MemberAuthor

Tested and confirmed end-to-end against the experimental fork: the publish flow and the backfill workflow both produced the immutable per-arch snapshot tags as expected.

@fnandofnando self-assigned this Aug 20, 2026
@fnandofnando added this to DevXAug 20, 2026
@github-project-automationgithub-project-automationBot moved this to Backlog (Not Ready) in DevXAug 20, 2026
@fnandofnando moved this from Backlog (Not Ready) to Needs Review in DevXAug 20, 2026
@fnando
fnando requested review from a team and leighmccullochAugust 20, 2026 00:04

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds immutable, per-release architecture tags to preserve SEP-58 image digests, plus tooling to backfill historical releases.

Changes:

  • Introduces uniform release iteration tags beginning at -0.
  • Publishes per-architecture snapshot tags and documents them.
  • Adds a provenance-based backfill workflow and tests.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
.github/workflows/backfill.ymlAdds manual backfill workflow.
.github/workflows/publish.ymlPropagates iteration into publishing.
RELEASE.mdDocuments snapshots and backfilling.
docker/README.mdDocuments mutable and immutable tags.
scripts/backfill_iteration_tags.pyReconstructs historical snapshot tags.
scripts/lib/gh_cli.pyAdds branch, file, and asset helpers.
scripts/publish_aliases.pyClarifies moving-alias behavior.
scripts/publish_manifests.pyCreates per-architecture snapshot tags.
scripts/release_body.pyLists snapshots in release bodies.
scripts/release_pr_body.pyHandles iteration-zero releases.
scripts/release_prepare.pySelects iteration tags using releases and branches.
tests/integration/test_release_prepare.pyTests iteration selection.
tests/unit/test_backfill_iteration_tags.pyTests backfill behavior.
tests/unit/test_publish_aliases.pyVerifies aliases exclude snapshots.
tests/unit/test_publish_manifests.pyTests snapshot publication.
tests/unit/test_release_body.pyTests snapshot release documentation.
tests/unit/test_release_pr_body.pyTests iteration-zero PR content.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadscripts/lib/gh_cli.py
Comment threadscripts/publish_manifests.py Outdated
Comment threadscripts/backfill_iteration_tags.py Outdated
@fnando
fnandoforce-pushed the immutable-iteration-tags branch from 694f928 to e839478CompareAugust 21, 2026 13:42
@fnando
fnandoforce-pushed the immutable-iteration-tags branch from e839478 to 31092eeCompareAugust 21, 2026 13:43

@leighmccullochleighmcculloch left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple comments, otherwise lgtm.

Comment threadscripts/backfill_iteration_tags.py Outdated
Comment threadscripts/publish_manifests.py Outdated
@fnando
fnando enabled auto-merge (squash) August 26, 2026 13:48
@fnando
fnando merged commit 332b6b4 into mainAug 26, 2026
12 checks passed
@fnando
fnando deleted the immutable-iteration-tags branch August 26, 2026 14:01
@github-project-automationgithub-project-automationBot moved this from Needs Review to Done in DevXAug 26, 2026
Comment threadscripts/lib/gh_cli.py
def list_release_branch_tags(repo: str) -> list[str]:
"""Release tags of the `release/<tag>` branches that exist on the repo.

A release branch is created at prepare time and persists across the

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we use 'delete branch on merge' on most repos, and so GitHub will auto delete the release branch, is that an issue?

cli = args.stellar_cli_version
registry = args.registry

iteration = latest_iteration(gh_cli.list_release_tags(args.repo), cli)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If v25.2.0 and v25.2.0-1 both exist as GitHub Releases, but v25.2.0-1's publish run fails before the build/push step, will backfill work as expected? Or will a next run get stuck?

Comment threadRELEASE.md
Moving aliases (`:<cli>`, `:latest`) re-point each release.
Moving aliases (`:<cli>`, `:latest`) re-point each release. The immutable `:<cli>-rust<key>-<arch>-<N>` snapshots are the exception — they're keyed by the release's refresh index, so a re-run recreates the same tags at the same digests rather than moving them.

To recover from a failed run, use **Re-run failed jobs** from the GitHub Actions UI; re-runs simply rebuild and overwrite. Recovering from a corrupt push is the same — just re-run, no manual tag deletion needed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think some of the text here needs updating. Are the statements about rerunning still correct? Won't that result in new releases now? Could it get stuck trying to republish an existing?

# auto-picked by the release workflow. Strip leading "v" and the
# trailing "-<N>" to derive the stellar-cli version; the refresh
# index N (0 when there's no suffix, i.e. the first release) names
# the immutable :<version>-<N> Docker tag published by the aliases

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is :<version>-<N> still exist, or the tag is :<cli>-rust<key>-<arch>-<N> now?

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Re-publishing version tags orphans previously published digests — which SEP-58 bldimg pins on chain permanently

3 participants

@fnando@leighmcculloch
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Tag every published per-arch image with an immutable per-release snapshot - #41

Merged
fnando merged 6 commits into
mainfrom
immutable-iteration-tags
Aug 26, 2026
Merged

Tag every published per-arch image with an immutable per-release snapshot#41
fnando merged 6 commits into
mainfrom
immutable-iteration-tags

Conversation

@fnando

Copy link
Copy Markdown
Member

Fixes#38.

What

Adds an immutable per-release snapshot tag for every published per-arch image: :‹cli›-rust‹key›-‹arch›-‹N› (e.g. 27.0.0-rust1.95.0-slim-trixie-amd64-0), minted by the publish workflow for each (rust base, arch) a release builds. Also adds a manually-dispatched backfill workflow to reconstruct these tags for already-published releases, recovering each per-arch digest from the release's prov-*.intoto.jsonl attestation assets.

Why

SEP-58 verifiable builds pin per-arch content digests (bldimg) into deployed contracts permanently. Today those digests are only reachable through mutable tags (:‹cli›-rust‹key›-‹arch›, :‹cli›, :latest), which re-point on the next publish — orphaning the old digest and making it garbage-collectable. The immutable per-arch tags keep every published digest referenced by a tag that never moves, so none can be garbage-collected. Coverage is per-arch across every rust pair a release built, not just the default one (e.g. v27.0.0 shipped four rust pairs).

CopilotAI balanced review requested due to automatic review settings August 20, 2026 00:00
@fnando

Copy link
Copy Markdown
MemberAuthor

Tested and confirmed end-to-end against the experimental fork: the publish flow and the backfill workflow both produced the immutable per-arch snapshot tags as expected.

@fnandofnando self-assigned this Aug 20, 2026
@fnandofnando added this to DevXAug 20, 2026
@github-project-automationgithub-project-automationBot moved this to Backlog (Not Ready) in DevXAug 20, 2026
@fnandofnando moved this from Backlog (Not Ready) to Needs Review in DevXAug 20, 2026
@fnando
fnando requested review from a team and leighmccullochAugust 20, 2026 00:04

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds immutable, per-release architecture tags to preserve SEP-58 image digests, plus tooling to backfill historical releases.

Changes:

  • Introduces uniform release iteration tags beginning at -0.
  • Publishes per-architecture snapshot tags and documents them.
  • Adds a provenance-based backfill workflow and tests.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
.github/workflows/backfill.ymlAdds manual backfill workflow.
.github/workflows/publish.ymlPropagates iteration into publishing.
RELEASE.mdDocuments snapshots and backfilling.
docker/README.mdDocuments mutable and immutable tags.
scripts/backfill_iteration_tags.pyReconstructs historical snapshot tags.
scripts/lib/gh_cli.pyAdds branch, file, and asset helpers.
scripts/publish_aliases.pyClarifies moving-alias behavior.
scripts/publish_manifests.pyCreates per-architecture snapshot tags.
scripts/release_body.pyLists snapshots in release bodies.
scripts/release_pr_body.pyHandles iteration-zero releases.
scripts/release_prepare.pySelects iteration tags using releases and branches.
tests/integration/test_release_prepare.pyTests iteration selection.
tests/unit/test_backfill_iteration_tags.pyTests backfill behavior.
tests/unit/test_publish_aliases.pyVerifies aliases exclude snapshots.
tests/unit/test_publish_manifests.pyTests snapshot publication.
tests/unit/test_release_body.pyTests snapshot release documentation.
tests/unit/test_release_pr_body.pyTests iteration-zero PR content.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadscripts/lib/gh_cli.py
Comment threadscripts/publish_manifests.py Outdated
Comment threadscripts/backfill_iteration_tags.py Outdated
@fnando
fnandoforce-pushed the immutable-iteration-tags branch from 694f928 to e839478CompareAugust 21, 2026 13:42
@fnando
fnandoforce-pushed the immutable-iteration-tags branch from e839478 to 31092eeCompareAugust 21, 2026 13:43

@leighmccullochleighmcculloch left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple comments, otherwise lgtm.

Comment threadscripts/backfill_iteration_tags.py Outdated
Comment threadscripts/publish_manifests.py Outdated
@fnando
fnando enabled auto-merge (squash) August 26, 2026 13:48
@fnando
fnando merged commit 332b6b4 into mainAug 26, 2026
12 checks passed
@fnando
fnando deleted the immutable-iteration-tags branch August 26, 2026 14:01
@github-project-automationgithub-project-automationBot moved this from Needs Review to Done in DevXAug 26, 2026
Comment threadscripts/lib/gh_cli.py
def list_release_branch_tags(repo: str) -> list[str]:
"""Release tags of the `release/<tag>` branches that exist on the repo.

A release branch is created at prepare time and persists across the

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we use 'delete branch on merge' on most repos, and so GitHub will auto delete the release branch, is that an issue?

cli = args.stellar_cli_version
registry = args.registry

iteration = latest_iteration(gh_cli.list_release_tags(args.repo), cli)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If v25.2.0 and v25.2.0-1 both exist as GitHub Releases, but v25.2.0-1's publish run fails before the build/push step, will backfill work as expected? Or will a next run get stuck?

Comment threadRELEASE.md
Moving aliases (`:<cli>`, `:latest`) re-point each release.
Moving aliases (`:<cli>`, `:latest`) re-point each release. The immutable `:<cli>-rust<key>-<arch>-<N>` snapshots are the exception — they're keyed by the release's refresh index, so a re-run recreates the same tags at the same digests rather than moving them.

To recover from a failed run, use **Re-run failed jobs** from the GitHub Actions UI; re-runs simply rebuild and overwrite. Recovering from a corrupt push is the same — just re-run, no manual tag deletion needed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think some of the text here needs updating. Are the statements about rerunning still correct? Won't that result in new releases now? Could it get stuck trying to republish an existing?

# auto-picked by the release workflow. Strip leading "v" and the
# trailing "-<N>" to derive the stellar-cli version; the refresh
# index N (0 when there's no suffix, i.e. the first release) names
# the immutable :<version>-<N> Docker tag published by the aliases

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is :<version>-<N> still exist, or the tag is :<cli>-rust<key>-<arch>-<N> now?

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Re-publishing version tags orphans previously published digests — which SEP-58 bldimg pins on chain permanently

3 participants

@fnando@leighmcculloch