feat: harden public Hermes primitive publication - #3
Merged
Conversation
Move exporter and validator behavior into small reusable modules (toolbox_common, sanitize_rules, candidate_policy, export_transaction, safety_checks, package_checks, public_manifest) behind unchanged CLI wrappers, and add a parser-based structure gate (verify-python-structure.py) enforcing 200-line files, 30-line constructs, and depth-3 control nesting. Equivalence witnessed: old (db735d9) and new exporters produced byte-identical skills/ and plugins/ trees from the same synthetic sources; the inventory manifest now derives plugin entries from repo contents instead of only the current sweep, matching the committed 23-plugin manifest.
RED: PYTHONDONTWRITEBYTECODE=1 python3 -m unittest tests.test_export_transaction -v failed 7/7 before implementation: the previous exporter deleted each destination before validation, so source-validation, sanitizer, interrupted- copy, and manifest-mismatch failures corrupted last-known-good packages, and unchanged packages were re-listed in the change list. Each candidate now stages into a temporary sibling directory, is sanitized deterministically, gets its manifest generated and cross-checked in staging, passes privacy/required-file checks there, and only then atomically replaces its own destination; byte-identical packages are skipped and omitted from the NUL-delimited change list. Destinations are never removed before a staged candidate validates, and a failed swap restores the previous package bytes.
Harden scripts/publish-public-candidates.sh and the publish mode of scripts/scan-public-candidates.py behind tests/test_publisher_contract.py: dirty worktree, checkout drift from origin/main, missing local plugin/profile allowlists, missing source-profile gate, missing repo-local git identity, validator failure, and failing repo tests all block commit and push; only NUL-listed accepted paths plus the deterministic inventory files are staged; no-candidate runs exit 0 with empty stdout; git add sweeps, --autostash, and git pull are banned statically. Split the scan main into gate functions to satisfy the 200/30/depth-3 structure limits. RED witnessed before implementation: PYTHONDONTWRITEBYTECODE=1 python3 -m unittest tests.test_publisher_contract -v -> FAILED (failures=10 of 14) against the previous scripts. GREEN: same command OK (14 tests); full suite 119 tests OK; structure, shell syntax, public-safety, identity-neutrality, and tutorial real-runtime validators all pass. Publisher cron remains paused.
Classify the current candidate inventory fail closed: publish eight current-source skills, retain the valid prompt-enhancer last-known-good package, and keep the validated validator personality. Remove 23 legacy tutorial plugins and the tutorial profile because the current public packages fail the no-test-double and 200/30 structural gates, while all 29 current plugin and 10 current profile candidates are rejected by the same public completeness policy. Candidate evidence remains local under .git/info.
Restart the skill slice after source drift, reclassify the candidate against the current fail-closed gates, and transactionally publish the accepted support-file update. No other candidate class changed.
Fail closed before staging when any candidate source path is a symlink, preventing an out-of-tree target from being copied into a public package. The regression test first demonstrated that the old exporter followed the link and then proves last-known-good preservation.
Record the symlink-hardening source and regression test in the deterministic public fingerprint inventory.
Extend the untracked identity denylist and rerun the transactional exporter so private business and family-profile identifiers are replaced in public copies. Include the newly accepted current-source plugin-builder reference discovered during the same drift-aware export.
Source fingerprints now cover exactly tracked files plus files beneath manifest-listed skill/plugin/profile/personality package roots, with a safe hidden-path-excluding walk fallback for non-git fixture repos, so unrelated untracked files such as .serena can no longer be ingested. The exporter wraps all selected exports, inventory writes, and the safety/identity/completeness/tutorial validators in a whole-batch transaction: any late candidate or validator failure restores every selected destination and both inventories byte-for-byte, removes newly created destinations, leaves no staging or backup residue, and emits no change list.
Run the tutorial-suite gate even when the suite is intentionally absent, so a partial tutorial reintroduction fails inside the whole-batch rollback boundary. Refresh the accepted integration-audit skill after verified source drift and regenerate exact inventory hashes.
Reclassify and export current public-safe plan-update-executor and plugin-builder source drift, then regenerate exact manifests and fingerprints after the full validation packet passes.
Create the Hermes venv and source-tree layout expected by the real PluginManager and profile-install tests, place its CLI on PATH, and keep PyYAML available to the workflow interpreter. A disposable CI-home simulation passed all 30 real-runtime/profile tests before this commit.
Owner
Author
|
Independent adversarial review identified privacy-sanitization, fingerprint-scope, symlink, and whole-batch rollback issues. Each was fixed with regression coverage. The final local packet passed 143 tests plus all validators, a disposable CI-runtime simulation passed the 30 real Hermes runtime/profile tests, both GitHub Actions runs are green, the 461-file remote PR set exactly matches the reviewed local diff, and manifest-listed package roots exactly match the public tree. The publisher remains paused pending post-merge verification. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
origin/main, repository-local identity, public GitHub visibility, local policy files, an exclusive lock, exact NUL-delimited staging, and the full validation packetCandidate and retention decisions
Safety and transaction behavior
Validation
hermes config checkKiren Srinivasan <kiren@fantasymetals.com>with no AI-authorship trailerPublication state
The automated publisher remains paused. It will not be resumed until this PR is green and merged, remote
mainand inventories are verified exactly, the original checkout is reconciled from the preserved backup, and two post-merge publisher no-op runs succeed.