Skip to content

fix(build): resolve OINK from candidate lock files - #497

Merged
imbajin merged 2 commits into
masterfrom
ci/oink-module-pin
Sep 22, 2026
Merged

imbajin merged 2 commits into
masterfrom
ci/oink-module-pin

Conversation

@imbajin

@imbajin imbajin commented Sep 22, 2026

Copy link
Copy Markdown
Member

Purpose of the PR

The trusted master workflow and the version builder both hard-code OINK 1.0.0 (including the migration tool checksum). This prevents staging a candidate pinned to a newer theme before merging that upgrade into production.

Resolve the theme and migration tool from the candidate site's go.mod / go.sum through one shared helper. Preserve site/module identity, checksum verification, the two-module dependency graph and the prohibition on replacements/exclusions. Accept valid blank lines in go.sum.

This prerequisite keeps master on OINK 1.0.0. It changes neither toolchain pins nor deployment destinations/guards. After it merges, #496 can use the existing trusted master workflow to deploy OINK 1.1 to staging first.

Validation

  • Actual module resolution with OINK 1.0.0 and 1.1.0 passed.
  • Five module-lock boundary tests, three workflow contracts and 75 versioning tests passed.
  • Historical 1.7 build and artifact validation passed: 219 canonical pages, 217 action manifests, 62,562 internal URLs and 17 contract routes.
  • Independent review of the complete diff and git diff --check passed.

- read the OINK requirement from candidate go.mod
- retain module integrity and replacement checks
- allow staging upgrades before production merges
@imbajin
imbajin marked this pull request as draft September 22, 2026 15:23
- share module identity and integrity validation
- remove the migration tool version and checksum literals
- accept valid blank lines in go.sum
- cover supported pins and dependency boundary failures
@imbajin imbajin changed the title fix(ci): honor candidate OINK pins for staging fix(build): resolve OINK from candidate lock files Sep 22, 2026
@imbajin
imbajin marked this pull request as ready for review September 22, 2026 15:32

@bitflicker64 bitflicker64 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Blocking: no. Summary: the resolver is correct and well covered - it reads the candidate's own go.mod/go.sum through overlay_shell, refuses a tampered checksum, and its five new tests pass - so these are all cleanups: the contributor-facing docs still state the hard v1.0.0 contract this PR replaces, lock-file mismatches now abort with a traceback instead of fail(), the GO_BIN resolution split in two, and hugo.yml no longer asserts anything about the theme that master controls. Evidence: python3 -m unittest discover -s scripts -p 'test_oink_module.py' -v passes; python3 scripts/oink_module.py against the real checkout with go1.27.0 exits 0 and prints oink@v1.0.0 with Sum/GoModSum matching go.sum; substituting h1:WRONG= into a scratch go.sum refuses the build, but as an uncaught CalledProcessError.

Comment thread scripts/oink_module.py
import subprocess
from pathlib import Path

MODULE = "github.com/pgsty/oink"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 The contributor docs still state the hard pin this PR replaces.

README.md:35 ("The module graph must resolve github.com/pgsty/oink@v1.0.0"), its Chinese mirror README.md:119, and contribution.md:33 ("must contain exactly the pinned github.com/pgsty/oink@v1.0.0 dependency for this site") are prescriptive statements of the verification contract. After this diff the enforced contract is "whatever go.mod pins, verified against go.sum" - locked_version() accepts any release version. The version they name happens to match master today, but the rule they describe is the one being removed here, and they are the instructions a contributor follows before editing.

Requested change: reword those three lines to describe the lock-file contract rather than a literal version, so they do not need editing again on the 1.1 bump.

Separately, for #496 rather than this PR: NOTICE:9 ("This product includes OINK v1.0.0") is still accurate on master but is now the only place the version is written by hand with nothing checking it. An assertion against locked_version()'s return would keep it honest across the bump.

Comment thread scripts/versioning.py
):
fail(f"unexpected OINK module metadata: {module!r}")
fail("Go executable is unavailable")
module = download_locked(assembly)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Lock-file mismatches now abort with a traceback instead of a clean fail().

The removed code ended in fail(f"unexpected OINK module metadata: {module!r}"), and fail raises SystemExit(message) (line 396) - one line, no traceback, and it printed the offending metadata. download_locked instead raises bare ValueErrors (scripts/oink_module.py:30,33,48,53,56,59) that carry no values, and command lets subprocess.CalledProcessError escape. main() (line 4513) has no handler, so both surface as tracebacks.

Reproduced by substituting h1:WRONG= for the archive hash in a scratch copy of go.sum:

subprocess.CalledProcessError: Command '['go', 'mod', 'download', '-json',
'github.com/pgsty/oink@v1.0.0']' returned non-zero exit status 1

and the go mod download JSON that would name the mismatch is discarded.

Requested change: put the actual and expected values into each ValueError message, and wrap this call so ValueError and CalledProcessError are reported through fail() like every other build error in this file.

Comment thread scripts/versioning.py
hugo = os.environ.get("HUGO_BIN", "hugo")
go = os.environ.get("GO_BIN", "go")
go_executable = shutil.which(go)
go_executable = shutil.which(os.environ.get("GO_BIN", "go"))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 GO_BIN is now resolved twice, and the failure message lost the value.

This line keeps guarding line 4135, where go_executable sets the PATH Hugo inherits, so the check must stay. But the old code passed go_executable straight into the go mod download subprocess, which made it the single resolution point; oink_module.command now re-reads os.environ.get("GO_BIN", "go") raw, so the binary that validates the lock files and the binary prepended to Hugo's PATH are resolved independently and can differ. The message on line 4075 also dropped the value - it was fail(f"Go executable is unavailable: {go}") before, which told the operator what GO_BIN had been set to.

Requested change: pass the resolved go_executable into download_locked/command so one path is used end to end, and restore the value in the failure message.

test "$(go list -m all | wc -l)" -eq 2
test "$(go list -m -f '{{ .Path }}@{{ .Version }}' github.com/pgsty/oink)" = "github.com/pgsty/oink@v1.0.0"
test -z "$(go list -m -f '{{ with .Replace }}{{ .Path }}@{{ .Version }}{{ end }}' github.com/pgsty/oink)"
python3 scripts/oink_module.py

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 On the dispatch path this step no longer asserts anything master controls.

prepare requires test "$GITHUB_REF" = "refs/heads/master" (line 124), so this YAML is always master's, but source_sha is the resolved candidate branch head (line 159) and the build job checks that out (line 204). The five inline assertions this replaces were therefore master-authoritative against the candidate's go.mod; scripts/oink_module.py comes out of the candidate checkout, so the step is now self-attested. The following step already runs candidate versioning.py, so this is not a new execution boundary - what is lost is the one cheap master-side check that would catch accidental drift in a candidate's go.mod before a staging build.

Requested change: keep a version-independent assertion inline alongside the helper call, so master still bounds the graph while the version floats:

test "$(go list -m -f '{{ .Path }}')" = "github.com/apache/hugegraph-doc"
test "$(go list -m all | wc -l)" -eq 2
test -z "$(go list -m -f '{{ with .Replace }}{{ .Path }}{{ end }}' github.com/pgsty/oink)"
python3 scripts/oink_module.py

@imbajin
imbajin merged commit a5a9861 into master Sep 22, 2026
11 checks passed
@imbajin
imbajin deleted the ci/oink-module-pin branch September 22, 2026 19:57
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.

3 participants