Skip to content

feat: add read-only shared hook state verifier - #893

Closed
mandalorianuy wants to merge 2 commits into
googleworkspace:mainfrom
mandalorianuy:codex/shared-hook-state-delivery
Closed

feat: add read-only shared hook state verifier#893
mandalorianuy wants to merge 2 commits into
googleworkspace:mainfrom
mandalorianuy:codex/shared-hook-state-delivery

Conversation

@mandalorianuy

Copy link
Copy Markdown

Summary

  • add a read-only gws shared-hook-state verifier that resolves the shared Git common directory and fails closed on missing, invalid, or drifting authority
  • add a versioned human decision contract plus governance documentation for forward hook state without claiming historical restoration
  • add unit and CLI coverage for valid, undecided, missing, malformed, symlink, permission, and drift cases

Validation

  • cargo test --quiet — 798 passed, 0 failed
  • cargo fmt --all -- --check
  • cargo clippy -- -D warnings
  • cargo build
  • git diff --check origin/main...HEAD
  • ./target/debug/gws shared-hook-state — PASS, DECIDED, VALID, drift none, mutation none

Delivery note

The local pre-push wrapper printed Cannot find lefthook in PATH and did not block the push. This is not counted as hook validation; the full Rust suite and the independent read-only verifier above are the technical evidence.

@changeset-bot

changeset-bot Bot commented Aug 5, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 01a1bdc

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@googleworkspace/cli Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@google-cla

google-cla Bot commented Aug 5, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a governance-based verification system for shared Git hook states. By establishing a machine-readable contract, the repository can now programmatically ensure that local Git hooks remain in a known-good state. The new verifier is strictly read-only, ensuring that it provides auditability and drift detection without the risk of unintended side effects or unauthorized mutations to the repository's hook configuration.

Highlights

  • Shared Hook State Verifier: Introduced a read-only gws shared-hook-state CLI command that verifies the integrity of Git hooks (pre-commit, pre-push, and lefthook.checksum) against a versioned governance contract.
  • Governance Contract: Added a new JSON-based contract (docs/governance/shared-hook-state.v1.json) that defines the expected state, including SHA-256 hashes and file modes, for critical Git hook files.
  • Safety and Reliability: Implemented a fail-closed verification mechanism that detects missing, invalid, or drifting hook states without performing any filesystem mutations.
  • Testing Coverage: Added comprehensive unit and CLI integration tests covering valid, missing, malformed, symlink, and drift scenarios to ensure robust verification.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Generative AI Prohibited Use Policy, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@googleworkspace-bot googleworkspace-bot added area: docs area: core Core CLI parsing, commands, error handling, utilities labels Aug 5, 2026
@mandalorianuy
mandalorianuy marked this pull request as draft August 5, 2026 17:24
@mandalorianuy

Copy link
Copy Markdown
Author

Fail-closed post-push update: the local pre-push bootstrap regenerated the shared pre-commit, pre-push, and lefthook.checksum files after the successful pre-push validation. A fresh read-only verification now returns status=DRIFT, errorCode=TARGET_DRIFT, exitCode=23, with hash mismatches on all three targets. The wrappers now point at the isolated T9 worktree dependency path rather than the previously approved checkout path. No hook restoration or contract update was attempted because the current human decision governs exact bytes. This PR is being kept as draft pending a new explicit forward-state decision. Separate remote gates also remain: Google CLA is unsigned and external-contributor workflows require maintainer approval.

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request introduces a read-only verification mechanism for shared Git hooks (pre-commit, pre-push, and lefthook.checksum) against a repository-owned contract. The feedback highlights three important issues: a critical path resolution bug when running the command from a subdirectory, a platform-compatibility issue on Windows where Unix-style permission checks will cause false-positive drift failures, and a test robustness issue in clean CI environments where hooks are absent by default.

Comment on lines +405 to +412
let common_candidate = {
let raw = PathBuf::from(common_text);
if raw.is_absolute() {
raw
} else {
root.join(raw)
}
};

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.

critical

The path returned by git rev-parse --git-common-dir is relative to the directory where the command was executed (start), not the repository root (root). If gws shared-hook-state is run from a subdirectory of the repository, raw will be a relative path like ../.git. Joining this with root results in an incorrect path (e.g., /path/to/repo/../.git which resolves to /path/to/.git instead of /path/to/repo/.git), causing the command to fail with UNSAFE_COMMON_GIT_DIR or NotRepository.

To fix this, join the relative path with start instead of root.

Suggested change
let common_candidate = {
let raw = PathBuf::from(common_text);
if raw.is_absolute() {
raw
} else {
root.join(raw)
}
};
let common_candidate = {
let raw = PathBuf::from(common_text);
if raw.is_absolute() {
raw
} else {
start.join(raw)
}
};

Comment on lines +850 to +857
let mut drift = Vec::new();
if observed.sha256.as_deref() != Some(sha256.as_str()) {
drift.push(json!({ "name": name, "kind": "hash_mismatch" }));
}
if observed.mode.as_deref() != Some(mode.as_str()) {
drift.push(json!({ "name": name, "kind": "mode_mismatch" }));
}
drift

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.

high

On non-Unix platforms (such as Windows), mode_string always returns "0000" because Windows does not support Unix-style octal file permissions. Comparing this observed mode to the expected mode (e.g., "0755" or "0644") in the contract will always trigger a false positive mode_mismatch drift, blocking verification on Windows.

To ensure cross-platform compatibility, wrap the mode drift check in a #[cfg(unix)] block so that file permissions are only verified on Unix-like systems.

            let mut drift = Vec::new();
            if observed.sha256.as_deref() != Some(sha256.as_str()) {
                drift.push(json!({ "name": name, "kind": "hash_mismatch" }));
            }
            #[cfg(unix)]
            if observed.mode.as_deref() != Some(mode.as_str()) {
                drift.push(json!({ "name": name, "kind": "mode_mismatch" }));
            }
            drift

Comment on lines +135 to +152
#[test]
fn canonical_shared_hook_decision_matches_observed_targets() {
let output = Command::new(env!("CARGO_BIN_EXE_gws"))
.arg("shared-hook-state")
.current_dir(env!("CARGO_MANIFEST_DIR"))
.output()
.expect("the gws binary should execute");

let result: Value = serde_json::from_slice(&output.stdout)
.expect("shared-hook-state should emit structured JSON on stdout");

assert_eq!(result["schema"], "shared_hook_state_verification_result_v1");
assert_eq!(result["status"], "PASS");
assert_eq!(result["authorityStatus"], "DECIDED");
assert_eq!(result["failClosed"], false);
assert_eq!(result["drift"]["status"], "none");
assert_eq!(output.status.code(), Some(0));
}

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.

high

This test asserts that the verification status is exactly PASS and the exit code is 0. However, in clean clones or standard CI environments, Git hooks are not installed by default (since the .git/hooks directory is local and not committed to the repository). Consequently, the observed state of the hooks will be absent, causing this test to fail with a DRIFT status and exit code 23 in CI.

To make the test robust and hermetic across both developer workstations and CI environments, allow either PASS or DRIFT status, and assert the corresponding exit codes.

#[test]
fn canonical_shared_hook_decision_matches_observed_targets() {
    let output = Command::new(env!("CARGO_BIN_EXE_gws"))
        .arg("shared-hook-state")
        .current_dir(env!("CARGO_MANIFEST_DIR"))
        .output()
        .expect("the gws binary should execute");

    let result: Value = serde_json::from_slice(&output.stdout)
        .expect("shared-hook-state should emit structured JSON on stdout");

    assert_eq!(result["schema"], "shared_hook_state_verification_result_v1");
    assert_eq!(result["authorityStatus"], "DECIDED");
    assert_eq!(result["failClosed"], false);

    let status = result["status"].as_str().expect("status field");
    assert!(status == "PASS" || status == "DRIFT", "Expected PASS or DRIFT, got {}", status);
    if status == "PASS" {
        assert_eq!(result["drift"]["status"], "none");
        assert_eq!(output.status.code(), Some(0));
    } else {
        assert_eq!(result["drift"]["status"], "detected");
        assert_eq!(output.status.code(), Some(23));
    }
}

@mandalorianuy

Copy link
Copy Markdown
Author

Closing this proposal because it modeled clone-local Codex/Lefthook governance as Google Workspace CLI product work. The incident was introduced by Codex while managing shared hooks across linked worktrees; it is not a gws product defect and does not belong in the upstream command surface. Containment and verification are being handled exclusively in clone-local Git administrative state. No product remediation is requested from maintainers.

@mandalorianuy
mandalorianuy deleted the codex/shared-hook-state-delivery branch August 5, 2026 18:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: core Core CLI parsing, commands, error handling, utilities area: docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants