🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

gitpin

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

gitpin - npm Package Compare versions

Comparing version
0.5.3
to
0.6.0
+79
action.yml
name: GitPin Evidence Gate
description: Verify that material PR claims cover the actual diff and point to exact committed evidence.
author: Sarosh Hussain
branding:
icon: check-square
color: green
inputs:
base-sha:
description: Full base commit SHA from github.event.pull_request.base.sha.
required: true
head-sha:
description: Full head commit SHA from github.event.pull_request.head.sha.
required: true
policy-path:
description: Trusted gate policy path read from the base commit.
required: false
default: .gitpin/gate.yml
repository-name:
description: Name used in generated full-SHA citations.
required: false
default: ""
gitpin-version:
description: Exact npm version to execute. Override only from a trusted workflow.
required: false
default: 0.6.0
outputs:
report-path:
description: Path to the deterministic JSON gate report.
value: ${{ steps.gate.outputs.report-path }}
report-id:
description: Stable identifier for this gate result.
value: ${{ steps.gate.outputs.report-id }}
status:
description: ok or failed.
value: ${{ steps.gate.outputs.status }}
runs:
using: composite
steps:
- name: Set up Node.js
uses: actions/setup-node@v7
with:
node-version: 24
- name: Verify PR evidence
id: gate
shell: bash
env:
BASE_SHA: ${{ inputs.base-sha }}
HEAD_SHA: ${{ inputs.head-sha }}
POLICY_PATH: ${{ inputs.policy-path }}
REPOSITORY_NAME: ${{ inputs.repository-name }}
GITPIN_VERSION: ${{ inputs.gitpin-version }}
NPM_CONFIG_REGISTRY: https://registry.npmjs.org
run: |
set -uo pipefail
REPORT_PATH="${RUNNER_TEMP}/gitpin-gate-report.json"
REPOSITORY_NAME="${REPOSITORY_NAME:-${GITHUB_REPOSITORY:-repository}}"
EMPTY_NPMRC="${RUNNER_TEMP}/gitpin-empty.npmrc"
: > "$EMPTY_NPMRC"
cd "$RUNNER_TEMP"
set +e
npm exec --yes \
--registry="https://registry.npmjs.org" \
--userconfig="$EMPTY_NPMRC" \
--package="gitpin@${GITPIN_VERSION}" -- gitpin gate \
--root "$GITHUB_WORKSPACE" \
--base "$BASE_SHA" \
--head "$HEAD_SHA" \
--policy "$POLICY_PATH" \
--repository "$REPOSITORY_NAME" > "$REPORT_PATH"
GATE_EXIT=$?
set -e
echo "report-path=$REPORT_PATH" >> "$GITHUB_OUTPUT"
node "${GITHUB_ACTION_PATH}/scripts/render-gate-action-report.mjs" "$REPORT_PATH"
exit "$GATE_EXIT"
export declare function runGateCommand(options: string[]): Promise<import("./gate-types").GateReport>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.runGateCommand = runGateCommand;
const gate_1 = require("./gate");
async function runGateCommand(options) {
let base;
let head;
let root;
let repository;
let policyPath;
for (let index = 0; index < options.length; index += 1) {
const option = options[index];
const value = options[index + 1];
if (!value || value.startsWith('--'))
throw new Error(`Option ${option} requires a value.`);
switch (option) {
case '--base':
base = value;
break;
case '--head':
head = value;
break;
case '--root':
root = value;
break;
case '--repository':
repository = value;
break;
case '--policy':
policyPath = value;
break;
default:
throw new Error(`Unknown gate option: ${option}. Run "gitpin help" for usage.`);
}
index += 1;
}
if (!base || !head)
throw new Error('gate requires --base <full-sha> and --head <full-sha>.');
return (0, gate_1.runGitPinGate)({
base,
head,
...(root ? { root } : {}),
...(repository ? { repository } : {}),
...(policyPath ? { policyPath } : {}),
});
}
//# sourceMappingURL=cli-gate.js.map
{"version":3,"file":"cli-gate.js","sourceRoot":"","sources":["../src/cli-gate.ts"],"names":[],"mappings":";;;AAAA,iCAAuC;AAEhC,KAAK,yBAAyB,OAAiB;IACpD,IAAI,IAAwB,CAAC;IAC7B,IAAI,IAAwB,CAAC;IAC7B,IAAI,IAAwB,CAAC;IAC7B,IAAI,UAA8B,CAAC;IACnC,IAAI,UAA8B,CAAC;IAEnC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACvD,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;QAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QACjC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,UAAU,MAAM,oBAAoB,CAAC,CAAC;QAC5F,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,QAAQ;gBACX,IAAI,GAAG,KAAK,CAAC;gBACb,MAAM;YACR,KAAK,QAAQ;gBACX,IAAI,GAAG,KAAK,CAAC;gBACb,MAAM;YACR,KAAK,QAAQ;gBACX,IAAI,GAAG,KAAK,CAAC;gBACb,MAAM;YACR,KAAK,cAAc;gBACjB,UAAU,GAAG,KAAK,CAAC;gBACnB,MAAM;YACR,KAAK,UAAU;gBACb,UAAU,GAAG,KAAK,CAAC;gBACnB,MAAM;YACR;gBACE,MAAM,IAAI,KAAK,CAAC,wBAAwB,MAAM,gCAAgC,CAAC,CAAC;QACpF,CAAC;QACD,KAAK,IAAI,CAAC,CAAC;IACb,CAAC;IACD,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC9F,OAAO,IAAA,oBAAa,EAAC;QACnB,IAAI;QACJ,IAAI;QACJ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzB,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtC,CAAC,CAAC;AACL,CAAC"}
import { type ChangeEvidence, type GatePolicy } from './gate-types';
export declare function resolveCommit(root: string, revision: string, label: string): string;
export declare function mergeBase(root: string, baseSha: string, headSha: string): string;
export declare function readPolicyAtBase(root: string, baseSha: string, policyPath: string): {
raw: string;
policy: GatePolicy;
};
export declare function readManifestAtHead(root: string, headSha: string, manifestPath: string, maxBytes: number): {
raw: string;
manifest: ChangeEvidence;
};
export declare function changedPaths(root: string, fromSha: string, headSha: string, limit: number): string[];
export declare function readGitFile(root: string, sha: string, sourcePath: string, maxBytes: number): string;
export declare function sha256(value: string): string;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveCommit = resolveCommit;
exports.mergeBase = mergeBase;
exports.readPolicyAtBase = readPolicyAtBase;
exports.readManifestAtHead = readManifestAtHead;
exports.changedPaths = changedPaths;
exports.readGitFile = readGitFile;
exports.sha256 = sha256;
const node_child_process_1 = require("node:child_process");
const node_crypto_1 = require("node:crypto");
const yaml_1 = require("yaml");
const gate_types_1 = require("./gate-types");
function resolveCommit(root, revision, label) {
if (!/^[0-9a-f]{40}$/iu.test(revision))
throw new Error(`${label} must be a full 40-character Git SHA.`);
try {
return gitText(root, ['rev-parse', '--verify', `${revision}^{commit}`], 1024)
.trim()
.toLowerCase();
}
catch {
throw new Error(`${label} commit ${revision} is unavailable.`);
}
}
function mergeBase(root, baseSha, headSha) {
try {
return gitText(root, ['merge-base', baseSha, headSha], 1024).trim().toLowerCase();
}
catch {
throw new Error(`No merge base exists between ${baseSha} and ${headSha}.`);
}
}
function readPolicyAtBase(root, baseSha, policyPath) {
const raw = readGitText(root, baseSha, policyPath, 1024 * 1024);
let parsed;
try {
parsed = (0, yaml_1.parse)(raw);
}
catch (error) {
throw new Error(`Trusted gate policy ${policyPath} is invalid YAML: ${errorMessage(error)}`);
}
const result = gate_types_1.gatePolicySchema.safeParse(parsed);
if (!result.success)
throw new Error(`Trusted gate policy ${policyPath} is invalid: ${result.error.message}`);
return { raw, policy: result.data };
}
function readManifestAtHead(root, headSha, manifestPath, maxBytes) {
const raw = readGitText(root, headSha, manifestPath, maxBytes);
let parsed;
try {
parsed = JSON.parse(raw);
}
catch (error) {
throw new Error(`Evidence manifest ${manifestPath} is invalid JSON: ${errorMessage(error)}`);
}
const result = gate_types_1.changeEvidenceSchema.safeParse(parsed);
if (!result.success)
throw new Error(`Evidence manifest ${manifestPath} is invalid: ${result.error.message}`);
return { raw, manifest: result.data };
}
function changedPaths(root, fromSha, headSha, limit) {
const output = gitText(root, ['diff', '--name-only', '--no-renames', '-z', fromSha, headSha, '--'], 10 * 1024 * 1024);
const paths = output.split('\0').filter(Boolean).sort();
if (paths.length > limit)
throw new Error(`Change has ${paths.length} paths; trusted policy limit is ${limit}.`);
return paths;
}
function readGitFile(root, sha, sourcePath, maxBytes) {
return readGitText(root, sha, sourcePath, maxBytes);
}
function sha256(value) {
return (0, node_crypto_1.createHash)('sha256').update(value, 'utf8').digest('hex');
}
function readGitText(root, sha, sourcePath, maxBytes) {
try {
const value = gitText(root, ['show', `${sha}:${sourcePath}`], maxBytes);
if (Buffer.byteLength(value, 'utf8') > maxBytes)
throw new Error('file exceeds byte limit');
return value;
}
catch (error) {
throw new Error(`Cannot read ${sourcePath} at ${sha}: ${errorMessage(error)}`);
}
}
function gitText(root, args, maxBuffer) {
return (0, node_child_process_1.execFileSync)('git', ['--no-replace-objects', ...args], {
cwd: root,
encoding: 'utf8',
env: { ...process.env, GIT_NO_REPLACE_OBJECTS: '1' },
maxBuffer,
windowsHide: true,
});
}
function errorMessage(error) {
return error instanceof Error ? error.message : String(error);
}
//# sourceMappingURL=gate-policy.js.map
{"version":3,"file":"gate-policy.js","sourceRoot":"","sources":["../src/gate-policy.ts"],"names":[],"mappings":"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"}
import { z } from 'zod';
declare const evidenceLocatorSchema: z.ZodObject<{
ref: z.ZodEnum<{
base: "base";
head: "head";
}>;
path: z.ZodString;
lineStart: z.ZodNumber;
lineEnd: z.ZodNumber;
contentSha256: z.ZodString;
}, z.core.$strict>;
export declare const changeEvidenceSchema: z.ZodObject<{
schemaVersion: z.ZodLiteral<1>;
summary: z.ZodString;
claims: z.ZodArray<z.ZodObject<{
id: z.ZodString;
statement: z.ZodString;
covers: z.ZodArray<z.ZodString>;
evidence: z.ZodArray<z.ZodObject<{
ref: z.ZodEnum<{
base: "base";
head: "head";
}>;
path: z.ZodString;
lineStart: z.ZodNumber;
lineEnd: z.ZodNumber;
contentSha256: z.ZodString;
}, z.core.$strict>>;
}, z.core.$strict>>;
}, z.core.$strict>;
export declare const gatePolicySchema: z.ZodObject<{
schemaVersion: z.ZodLiteral<1>;
manifestPath: z.ZodDefault<z.ZodString>;
coverage: z.ZodDefault<z.ZodObject<{
include: z.ZodDefault<z.ZodArray<z.ZodString>>;
exclude: z.ZodDefault<z.ZodArray<z.ZodString>>;
}, z.core.$strict>>;
policyChanges: z.ZodDefault<z.ZodEnum<{
allow: "allow";
block: "block";
}>>;
limits: z.ZodDefault<z.ZodObject<{
changedPaths: z.ZodDefault<z.ZodNumber>;
claims: z.ZodDefault<z.ZodNumber>;
evidencePerClaim: z.ZodDefault<z.ZodNumber>;
fileBytes: z.ZodDefault<z.ZodNumber>;
}, z.core.$strict>>;
}, z.core.$strict>;
export type ChangeEvidence = z.infer<typeof changeEvidenceSchema>;
export type GatePolicy = z.infer<typeof gatePolicySchema>;
export type EvidenceLocator = z.infer<typeof evidenceLocatorSchema>;
export interface GateViolation {
code: string;
message: string;
path?: string;
claimId?: string;
}
export interface VerifiedLocator {
ref: 'base' | 'head';
path: string;
lineStart: number;
lineEnd: number;
expectedContentSha256: string;
actualContentSha256: string | null;
status: 'verified' | 'failed';
citation: string | null;
handle: string | null;
}
export interface GateClaimReport {
id: string;
statement: string;
status: 'evidence-verified' | 'failed';
covers: string[];
evidence: VerifiedLocator[];
}
export interface GateReport {
kind: 'gitpin-gate-report';
schemaVersion: 1;
status: 'ok' | 'failed';
reportId: string;
repository: string;
baseSha: string;
headSha: string;
mergeBaseSha: string;
policy: {
path: string;
sha256: string;
};
manifest: {
path: string;
sha256: string;
};
changedPaths: {
all: string[];
required: string[];
uncovered: string[];
};
claims: GateClaimReport[];
violations: GateViolation[];
message: string;
}
export declare function isSafeRelativePath(value: string): boolean;
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.gatePolicySchema = exports.changeEvidenceSchema = void 0;
exports.isSafeRelativePath = isSafeRelativePath;
const zod_1 = require("zod");
const relativePath = zod_1.z
.string()
.min(1)
.max(500)
.refine((value) => isSafeRelativePath(value), 'Must be a normalized repository-relative path.');
const evidenceLocatorSchema = zod_1.z
.object({
ref: zod_1.z.enum(['base', 'head']),
path: relativePath,
lineStart: zod_1.z.number().int().positive(),
lineEnd: zod_1.z.number().int().positive(),
contentSha256: zod_1.z.string().regex(/^[0-9a-f]{64}$/u),
})
.strict()
.refine((value) => value.lineEnd >= value.lineStart, 'lineEnd must be greater than or equal to lineStart.');
const claimSchema = zod_1.z
.object({
id: zod_1.z.string().regex(/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/u),
statement: zod_1.z.string().min(1).max(1000),
covers: zod_1.z.array(relativePath).min(1).max(100),
evidence: zod_1.z.array(evidenceLocatorSchema).min(1).max(16),
})
.strict();
exports.changeEvidenceSchema = zod_1.z
.object({
schemaVersion: zod_1.z.literal(1),
summary: zod_1.z.string().min(1).max(2000),
claims: zod_1.z.array(claimSchema).max(100),
})
.strict();
exports.gatePolicySchema = zod_1.z
.object({
schemaVersion: zod_1.z.literal(1),
manifestPath: relativePath.default('.gitpin/change-evidence.json'),
coverage: zod_1.z
.object({
include: zod_1.z.array(zod_1.z.string().min(1).max(500)).min(1).default(['**']),
exclude: zod_1.z.array(zod_1.z.string().min(1).max(500)).default([]),
})
.strict()
.default({ include: ['**'], exclude: [] }),
policyChanges: zod_1.z.enum(['block', 'allow']).default('block'),
limits: zod_1.z
.object({
changedPaths: zod_1.z.number().int().min(1).max(1000).default(100),
claims: zod_1.z.number().int().min(1).max(100).default(50),
evidencePerClaim: zod_1.z.number().int().min(1).max(16).default(8),
fileBytes: zod_1.z
.number()
.int()
.min(1024)
.max(10 * 1024 * 1024)
.default(2 * 1024 * 1024),
})
.strict()
.default({ changedPaths: 100, claims: 50, evidencePerClaim: 8, fileBytes: 2 * 1024 * 1024 }),
})
.strict();
function isSafeRelativePath(value) {
if (!value || value.includes('\0') || value.includes('\\') || value.startsWith('/') || /^[A-Za-z]:/u.test(value)) {
return false;
}
const segments = value.split('/');
return !segments.some((segment) => segment === '' || segment === '.' || segment === '..');
}
//# sourceMappingURL=gate-types.js.map
{"version":3,"file":"gate-types.js","sourceRoot":"","sources":["../src/gate-types.ts"],"names":[],"mappings":"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"}
import { type GateReport } from './gate-types';
export declare function runGitPinGate(input: {
root?: string;
repository?: string;
base: string;
head: string;
policyPath?: string;
}): Promise<GateReport>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.runGitPinGate = runGitPinGate;
const node_crypto_1 = require("node:crypto");
const node_path_1 = require("node:path");
const evidence_citation_1 = require("./evidence-citation");
const policy_1 = require("./policy");
const gate_policy_1 = require("./gate-policy");
const gate_types_1 = require("./gate-types");
const DEFAULT_POLICY_PATH = '.gitpin/gate.yml';
async function runGitPinGate(input) {
const root = (0, node_path_1.resolve)(input.root ?? process.cwd());
const repository = input.repository ?? (0, node_path_1.basename)(root);
const policyPath = input.policyPath ?? DEFAULT_POLICY_PATH;
if (!(0, gate_types_1.isSafeRelativePath)(policyPath))
throw new Error('--policy must be a normalized repository-relative path.');
const baseSha = (0, gate_policy_1.resolveCommit)(root, input.base, '--base');
const headSha = (0, gate_policy_1.resolveCommit)(root, input.head, '--head');
const mergeBaseSha = (0, gate_policy_1.mergeBase)(root, baseSha, headSha);
const policyResult = (0, gate_policy_1.readPolicyAtBase)(root, baseSha, policyPath);
const { policy } = policyResult;
const manifestResult = (0, gate_policy_1.readManifestAtHead)(root, headSha, policy.manifestPath, policy.limits.fileBytes);
if (manifestResult.manifest.claims.length > policy.limits.claims) {
throw new Error(`Evidence manifest has ${manifestResult.manifest.claims.length} claims; trusted policy limit is ${policy.limits.claims}.`);
}
const allChangedPaths = (0, gate_policy_1.changedPaths)(root, mergeBaseSha, headSha, policy.limits.changedPaths);
const violations = [];
const duplicateClaimIds = duplicates(manifestResult.manifest.claims.map((claim) => claim.id));
for (const id of duplicateClaimIds) {
violations.push({ code: 'duplicate-claim-id', claimId: id, message: `Claim ID ${id} is duplicated.` });
}
const requiredPaths = allChangedPaths.filter((path) => path !== policy.manifestPath &&
matchesAny(path, policy.coverage.include) &&
!matchesAny(path, policy.coverage.exclude));
if (policy.policyChanges === 'block' && allChangedPaths.includes(policyPath)) {
violations.push({
code: 'policy-change-blocked',
path: policyPath,
message: `Trusted gate policy changes must be merged separately: ${policyPath}.`,
});
}
const claims = [];
for (const claim of manifestResult.manifest.claims) {
const claimViolationsBefore = violations.length;
if (claim.evidence.length > policy.limits.evidencePerClaim) {
violations.push({
code: 'evidence-limit',
claimId: claim.id,
message: `Claim ${claim.id} has ${claim.evidence.length} evidence locators; limit is ${policy.limits.evidencePerClaim}.`,
});
}
for (const path of duplicates(claim.covers)) {
violations.push({
code: 'duplicate-cover',
claimId: claim.id,
path,
message: `Claim ${claim.id} covers ${path} twice.`,
});
}
const evidence = [];
for (const locator of claim.evidence.slice(0, policy.limits.evidencePerClaim)) {
const targetSha = locator.ref === 'base' ? baseSha : headSha;
let actualContentSha256 = null;
let citation = null;
let handle = null;
let status = 'verified';
if (locator.path === policy.manifestPath || (0, policy_1.isAlwaysSensitivePath)(locator.path)) {
status = 'failed';
violations.push({
code: locator.path === policy.manifestPath ? 'manifest-self-citation' : 'sensitive-evidence-path',
claimId: claim.id,
path: locator.path,
message: locator.path === policy.manifestPath
? `Claim ${claim.id} cannot cite the evidence manifest itself.`
: `Claim ${claim.id} cannot expose sensitive evidence path ${locator.path}.`,
});
}
else {
try {
const content = (0, gate_policy_1.readGitFile)(root, targetSha, locator.path, policy.limits.fileBytes);
const lines = content.split(/\r?\n/u);
if (locator.lineEnd > lines.length || locator.lineEnd - locator.lineStart + 1 > 200) {
throw new Error(`range ${locator.lineStart}-${locator.lineEnd} is outside the file or exceeds 200 lines`);
}
const slice = lines.slice(locator.lineStart - 1, locator.lineEnd).join('\n');
actualContentSha256 = (0, gate_policy_1.sha256)(slice);
if (actualContentSha256 !== locator.contentSha256) {
status = 'failed';
violations.push({
code: 'content-hash-mismatch',
claimId: claim.id,
path: locator.path,
message: `Claim ${claim.id} evidence hash does not match ${locator.ref}:${locator.path}:${locator.lineStart}-${locator.lineEnd}.`,
});
}
else {
const built = (0, evidence_citation_1.buildCitation)({
repository,
sourcePath: locator.path,
line: locator.lineStart,
lineEnd: locator.lineEnd,
commitSha: targetSha,
provenance: 'git-head',
});
citation = built.cite;
handle = built.handle;
}
}
catch (error) {
status = 'failed';
violations.push({
code: 'evidence-unavailable',
claimId: claim.id,
path: locator.path,
message: error instanceof Error ? error.message : String(error),
});
}
}
evidence.push({
ref: locator.ref,
path: locator.path,
lineStart: locator.lineStart,
lineEnd: locator.lineEnd,
expectedContentSha256: locator.contentSha256,
actualContentSha256,
status,
citation,
handle,
});
}
claims.push({
id: claim.id,
statement: claim.statement,
covers: [...new Set(claim.covers)].sort(),
evidence,
status: violations.length === claimViolationsBefore && evidence.every((item) => item.status === 'verified')
? 'evidence-verified'
: 'failed',
});
}
const coveredPaths = new Set(manifestResult.manifest.claims.flatMap((claim) => claim.covers));
const uncovered = requiredPaths.filter((path) => !coveredPaths.has(path));
for (const path of uncovered) {
violations.push({ code: 'uncovered-change', path, message: `Changed path has no material claim: ${path}.` });
}
const reportMaterial = {
repository,
baseSha,
headSha,
mergeBaseSha,
policySha256: (0, gate_policy_1.sha256)(policyResult.raw),
manifestSha256: (0, gate_policy_1.sha256)(manifestResult.raw),
allChangedPaths,
requiredPaths,
claims,
violations,
};
const status = violations.length === 0 ? 'ok' : 'failed';
return {
kind: 'gitpin-gate-report',
schemaVersion: 1,
status,
reportId: (0, node_crypto_1.createHash)('sha256').update(JSON.stringify(reportMaterial), 'utf8').digest('hex').slice(0, 16),
repository,
baseSha,
headSha,
mergeBaseSha,
policy: { path: policyPath, sha256: reportMaterial.policySha256 },
manifest: { path: policy.manifestPath, sha256: reportMaterial.manifestSha256 },
changedPaths: { all: allChangedPaths, required: requiredPaths, uncovered },
claims,
violations,
message: status === 'ok'
? `Checked ${claims.length} claim manifest entr${claims.length === 1 ? 'y' : 'ies'} and verified their evidence locators for ${requiredPaths.length} changed path(s) at ${headSha}.`
: `Gate failed with ${violations.length} violation(s). Evidence locators verify committed content, not semantic correctness.`,
};
}
function duplicates(values) {
const seen = new Set();
const repeated = new Set();
for (const value of values) {
if (seen.has(value))
repeated.add(value);
seen.add(value);
}
return [...repeated].sort();
}
function matchesAny(path, patterns) {
return patterns.some((pattern) => globRegex(pattern).test(path));
}
function globRegex(pattern) {
let source = '^';
for (let index = 0; index < pattern.length; index += 1) {
const character = pattern[index];
if (character === '*' && pattern[index + 1] === '*') {
if (pattern[index + 2] === '/') {
source += '(?:.*/)?';
index += 2;
}
else {
source += '.*';
index += 1;
}
}
else if (character === '*') {
source += '[^/]*';
}
else if (character === '?') {
source += '[^/]';
}
else {
source += character.replace(/[\\^$.[\]{}()+|]/gu, '\\$&');
}
}
return new RegExp(`${source}$`, 'u');
}
//# sourceMappingURL=gate.js.map
{"version":3,"file":"gate.js","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"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"}
# PR evidence gate
`gitpin gate` is a read-only required check for agent-authored and human-authored pull requests. It compares the actual merge-base diff with a committed change-evidence manifest, then verifies every evidence locator against an exact base or head commit.
It verifies **coverage, location, revision, and content hash**. It does not prove semantic correctness, successful runtime behavior, authorship, authorization, or compliance.
## Trust boundary
```text
trusted policy = git show <base>:.gitpin/gate.yml
submitted data = git show <head>:<policy.manifestPath>
actual change = git diff <merge-base(base,head)>..<head>
```
The gate never reads policy or evidence from the dirty working tree. A PR therefore cannot weaken its own policy. The manifest intentionally omits `headSha`: a committed file cannot contain the SHA of the commit that contains it. GitPin binds the manifest to `headSha` when it reads the file with `git show`, and emits full-SHA citations in the report.
## Bootstrap
Copy [`templates/gate.yml`](../templates/gate.yml) to `.gitpin/gate.yml` on the default branch. Policy installation must be a separate trusted change; the first protected PR can only run after the base branch contains the policy.
Every later PR commits `.gitpin/change-evidence.json`. Each material claim:
- lists the changed paths it covers;
- contains one or more exact base/head evidence locators;
- hashes the normalized line slice (`lineStart..lineEnd`, joined with `\n`) with SHA-256.
Base evidence supports deletions. The manifest itself is excluded from coverage and cannot cite itself. Sensitive paths cannot be exposed as evidence.
## GitHub Actions
```yaml
name: Agent delivery assurance
on:
pull_request:
permissions:
contents: read
jobs:
evidence:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
- uses: shmindmaster/gitpin@v0.6.0
with:
base-sha: ${{ github.event.pull_request.base.sha }}
head-sha: ${{ github.event.pull_request.head.sha }}
```
Use `pull_request`, never `pull_request_target`. Give the job `contents: read`, no secrets, and make it a required workflow with a GitHub ruleset so a PR cannot replace its own enforcement workflow.
## CrewScore named controls
CrewScore complements the evidence gate: it checks whether named written controls are present before execution. Keep it a separate required check and use explicit controls—not its aggregate coverage score.
```yaml
written-controls:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
- name: Load trusted CrewScore policy
shell: bash
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
run: git show "$BASE_SHA:.crewscore.yml" > "$RUNNER_TEMP/crewscore.yml"
- uses: shmindmaster/crewscore@v0.6.8
with:
scan-path: .
config: ${{ runner.temp }}/crewscore.yml
threshold: ""
```
CrewScore observes written text only. It does not prove runtime enforcement, agent obedience, certification, or compliance. Pin its Action version and ruleset, and keep `.crewscore.yml` on the trusted base branch.
## Local CLI
```bash
gitpin gate --base <full-40-character-sha> --head <full-40-character-sha>
```
Exit `0` means all required changed paths have material claims and all locators match committed content. Exit `1` means the gate failed. The deterministic JSON report goes to stdout.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://shmindmaster.github.io/gitpin/schemas/change-evidence.schema.json",
"title": "GitPin change evidence",
"type": "object",
"additionalProperties": false,
"required": ["schemaVersion", "summary", "claims"],
"properties": {
"schemaVersion": { "const": 1 },
"summary": { "type": "string", "minLength": 1, "maxLength": 2000 },
"claims": {
"type": "array",
"maxItems": 100,
"items": {
"type": "object",
"additionalProperties": false,
"required": ["id", "statement", "covers", "evidence"],
"properties": {
"id": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$" },
"statement": { "type": "string", "minLength": 1, "maxLength": 1000 },
"covers": {
"type": "array",
"minItems": 1,
"maxItems": 100,
"items": { "$ref": "#/$defs/path" }
},
"evidence": {
"type": "array",
"minItems": 1,
"maxItems": 16,
"items": {
"type": "object",
"additionalProperties": false,
"required": ["ref", "path", "lineStart", "lineEnd", "contentSha256"],
"properties": {
"ref": { "enum": ["base", "head"] },
"path": { "$ref": "#/$defs/path" },
"lineStart": { "type": "integer", "minimum": 1 },
"lineEnd": { "type": "integer", "minimum": 1 },
"contentSha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" }
}
}
}
}
}
}
},
"$defs": {
"path": {
"type": "string",
"minLength": 1,
"maxLength": 500,
"pattern": "^(?!/)(?![A-Za-z]:)(?!.*\\\\)(?!.*(?:^|/)\\.\\.?(?:/|$))(?!.*//)(?!.*\\/$).+$"
}
}
}
import { appendFileSync, readFileSync } from 'node:fs';
const reportPath = process.argv[2];
if (!reportPath) fail('Report path is required.');
let report;
try {
report = JSON.parse(readFileSync(reportPath, 'utf8'));
} catch {
fail('Gate did not produce a valid JSON report.');
}
if (
report?.kind !== 'gitpin-gate-report' ||
report.schemaVersion !== 1 ||
!['ok', 'failed'].includes(report.status) ||
!/^[0-9a-f]{16}$/u.test(report.reportId ?? '') ||
!Array.isArray(report.claims) ||
!Array.isArray(report.violations) ||
!Array.isArray(report.changedPaths?.required)
) {
fail('Gate report does not match gitpin-gate-report schema version 1.');
}
if (process.env.GITHUB_OUTPUT) {
appendFileSync(process.env.GITHUB_OUTPUT, `status=${report.status}\nreport-id=${report.reportId}\n`);
}
if (process.env.GITHUB_STEP_SUMMARY) {
const lines = [
'## GitPin Evidence Gate',
'',
`**Status:** ${report.status} · **Report:** \`${report.reportId}\``,
'',
report.message,
'',
`Changed paths requiring claims: ${report.changedPaths.required.length}`,
`Claims with verified evidence locators: ${report.claims.filter((claim) => claim.status === 'evidence-verified').length}/${report.claims.length}`,
];
if (report.violations.length) {
lines.push('', '### Violations', '');
for (const violation of report.violations.slice(0, 20)) lines.push(`- ${violation.message}`);
}
appendFileSync(process.env.GITHUB_STEP_SUMMARY, `${lines.join('\n')}\n`);
}
function fail(message) {
process.stderr.write(`::error title=GitPin Evidence Gate::${message}\n`);
process.exit(1);
}
{
"schemaVersion": 1,
"summary": "Describe the user-visible or operational outcome of this change.",
"claims": [
{
"id": "CHANGE-1",
"statement": "Describe one material claim without asserting more than the evidence shows.",
"covers": ["src/example.ts"],
"evidence": [
{
"ref": "head",
"path": "src/example.ts",
"lineStart": 1,
"lineEnd": 10,
"contentSha256": "0000000000000000000000000000000000000000000000000000000000000000"
}
]
}
]
}
schemaVersion: 1
manifestPath: .gitpin/change-evidence.json
coverage:
include:
- "**"
exclude:
- "docs/generated/**"
# A PR cannot weaken its own gate. Merge policy changes separately.
policyChanges: block
limits:
changedPaths: 100
claims: 50
evidencePerClaim: 8
fileBytes: 2097152
+13
-1

@@ -7,2 +7,13 @@ # Changelog

## [0.6.0] - 2026-07-31
### Added
- Add a read-only `gitpin gate` command that loads policy from the trusted base commit, binds a submitted manifest to the exact head commit, compares the merge-base diff, and verifies full-SHA line-slice evidence hashes.
- Add the GitPin Evidence Gate GitHub Action, deterministic JSON reports, base evidence for deletions, bootstrap templates, and documented CrewScore named-control composition.
### Changed
- Reposition GitPin around agent-delivery assurance and required PR evidence rather than repository-context retrieval.
## [0.5.3] - 2026-07-31

@@ -162,3 +173,4 @@

[Unreleased]: https://github.com/shmindmaster/gitpin/compare/v0.5.3...HEAD
[Unreleased]: https://github.com/shmindmaster/gitpin/compare/v0.6.0...HEAD
[0.6.0]: https://github.com/shmindmaster/gitpin/releases/tag/v0.6.0
[0.5.3]: https://github.com/shmindmaster/gitpin/releases/tag/v0.5.3

@@ -165,0 +177,0 @@ [0.5.2]: https://github.com/shmindmaster/gitpin/releases/tag/v0.5.2

@@ -5,2 +5,3 @@ "use strict";

const context_brief_1 = require("./context-brief");
const cli_gate_1 = require("./cli-gate");
const cli_verify_1 = require("./cli-verify");

@@ -46,2 +47,8 @@ const doctor_1 = require("./doctor");

}
if (command === 'gate') {
const report = await (0, cli_gate_1.runGateCommand)(options);
console.log(JSON.stringify(report, null, 2));
process.exitCode = (0, cli_verify_1.exitForVerify)(report);
return;
}
if (command === 'help' || command === '--help' || command === '-h') {

@@ -121,2 +128,3 @@ console.log(cliHelp());

gitpin prove-set --from-json <items.json>
gitpin gate --base <full-sha> --head <full-sha> [--root <repo>] [--policy <path>]

@@ -144,2 +152,3 @@ Init options:

Cite mini-spec: docs/cite-spec.md
PR evidence gate: docs/pr-evidence-gate.md
Migration: REPOCONTEXT_* env vars and ~/.repocontext still work as aliases.

@@ -146,0 +155,0 @@ GitPin writes briefs only to stdout. Redirect explicitly for artifacts.`;

+1
-1

@@ -1,1 +0,1 @@

{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;AAAA,mDAAuF;AACvF,6CAA4G;AAC5G,qCAA+E;AAC/E,yCAA8C;AAC9C,6CAA6F;AAEtF,KAAK,iBAAiB,IAAc;IACzC,MAAM,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC;IACnC,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QACzB,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QACvF,MAAM,MAAM,GAAG,MAAM,IAAA,wBAAe,GAAE,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,IAAA,2BAAkB,EAAC,MAAM,CAAC,CAAC,CAAC;QACxC,OAAO,CAAC,QAAQ,GAAG,IAAA,uBAAc,EAAC,MAAM,CAAC,CAAC;QAC1C,OAAO;IACT,CAAC;IACD,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,IAAA,+BAAe,EAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACxF,OAAO;IACT,CAAC;IACD,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,MAAM,IAAA,kCAAqB,EAAC,IAAA,6BAAgB,EAAC,OAAO,CAAC,CAAC,CAAC;QACtE,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC;QACtC,OAAO,CAAC,QAAQ,GAAG,IAAA,uBAAc,EAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACpD,OAAO;IACT,CAAC;IACD,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,MAAM,IAAA,6BAAgB,EAAC,OAAO,CAAC,CAAC;QAC/C,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7C,OAAO,CAAC,QAAQ,GAAG,IAAA,0BAAa,EAAC,MAAM,CAAC,CAAC;QACzC,OAAO;IACT,CAAC;IACD,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;QAC5B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,IAAA,2BAAgB,EAAC,IAAA,iCAAoB,EAAC,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5F,OAAO;IACT,CAAC;IACD,IAAI,OAAO,KAAK,cAAc,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,MAAM,IAAA,kCAAqB,EAAC,OAAO,CAAC,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7C,OAAO,CAAC,QAAQ,GAAG,IAAA,0BAAa,EAAC,MAAM,CAAC,CAAC;QACzC,OAAO;IACT,CAAC;IACD,IAAI,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACnE,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QACvB,OAAO;IACT,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,oBAAoB,OAAO,6CAA6C,CAAC,CAAC;AAC5F,CAAC;AAED,SAAS,iBAAiB,CAAC,OAAiB;IAC1C,IAAI,QAAQ,GAAkB,WAAW,CAAC;IAC1C,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,IAAI,gBAAoC,CAAC;IACzC,IAAI,IAAwB,CAAC;IAC7B,IAAI,IAAwB,CAAC;IAE7B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACvD,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;QAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QACjC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,UAAU,MAAM,oBAAoB,CAAC,CAAC;QAC5F,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,YAAY;gBACf,IAAI,CAAC,+BAAe,CAAC,QAAQ,CAAC,KAAsB,CAAC,EAAE,CAAC;oBACtD,MAAM,IAAI,KAAK,CAAC,4BAA4B,+BAAe,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC7E,CAAC;gBACD,QAAQ,GAAG,KAAsB,CAAC;gBAClC,MAAM;YACR,KAAK,cAAc;gBACjB,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACzB,MAAM;YACR,KAAK,qBAAqB;gBACxB,gBAAgB,GAAG,KAAK,CAAC;gBACzB,MAAM;YACR,KAAK,QAAQ;gBACX,IAAI,GAAG,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;gBACjC,MAAM;YACR,KAAK,QAAQ;gBACX,IAAI,GAAG,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;gBACjC,MAAM;YACR;gBACE,MAAM,IAAI,KAAK,CAAC,yBAAyB,MAAM,gCAAgC,CAAC,CAAC;QACrF,CAAC;QACD,KAAK,IAAI,CAAC,CAAC;IACb,CAAC;IAED,MAAM,YAAY,GAAG,CAAC,gBAAgB,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;IAC3E,IAAI,YAAY,KAAK,CAAC,IAAI,YAAY,KAAK,CAAC,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CAAC,4EAA4E,CAAC,CAAC;IAChG,CAAC;IACD,IAAI,gBAAgB,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAC5F,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;IAClF,CAAC;IACD,OAAO;QACL,QAAQ;QACR,GAAG,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChF,GAAG,CAAC,gBAAgB,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,UAAU,EAAE,gBAAgB,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC3G,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,KAAa,EAAE,MAAc;IAC7C,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,GAAG,MAAM,qDAAqD,CAAC,CAAC;IAClF,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,OAAO;IACd,OAAO;;;;;;;;;;;;;;;;wCAgB+B,iCAAoB,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;wEAqBC,CAAC;AACzE,CAAC;AAED,SAAS,gBAAgB,CAAC,MAAyD;IACjF,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC;IAClC,OAAO;QACL,uBAAuB,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE;QAChD,aAAa,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,GAAG;QAChG,IAAA,2BAAkB,EAAC,MAAM,CAAC,SAAS,CAAC;QACpC,EAAE;QACF,mBAAmB,KAAK,CAAC,SAAS,EAAE;QACpC,WAAW,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,IAAI,EAAE;QAC/D,WAAW,KAAK,CAAC,SAAS,EAAE;QAC5B,sCAAsC,KAAK,CAAC,UAAU,WAAW,KAAK,CAAC,UAAU,WAAW,KAAK,CAAC,IAAI,UAAU,KAAK,CAAC,SAAS,EAAE;QACjI,EAAE;QACF,yBAAyB,MAAM,CAAC,MAAM,IAAI;QAC1C,MAAM,CAAC,YAAY;QACnB,EAAE;QACF,+FAA+F;KAChG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}

@@ -197,3 +197,3 @@ "use strict";

name: 'GitPin',
version: '0.5.3',
version: '0.6.0',
schema: 'v1',

@@ -200,0 +200,0 @@ mcpServers: [{ name: 'GitPin', type: 'stdio', ...server }],

@@ -13,3 +13,3 @@ #!/usr/bin/env node

function createServer() {
const server = new mcp_js_1.McpServer({ name: 'gitpin', version: '0.5.3' });
const server = new mcp_js_1.McpServer({ name: 'gitpin', version: '0.6.0' });
(0, pin_tools_1.registerPinTools)(server);

@@ -16,0 +16,0 @@ (0, pin_prompt_1.registerProvePrompt)(server);

@@ -88,3 +88,3 @@ # MCP client setup (GitPin)

name: GitPin
version: 0.5.3
version: 0.6.0
schema: v1

@@ -91,0 +91,0 @@ mcpServers:

{
"name": "gitpin",
"version": "0.5.3",
"version": "0.6.0",
"mcpName": "io.github.shmindmaster/gitpin",
"type": "commonjs",
"description": "Prove and verify multi-repo agent claims at Git HEAD—index-free evidence packs with path, line, and full SHA.",
"description": "Verify agent-authored change claims at exact Git commits with an evidence-first PR gate and local MCP.",
"author": "Sarosh Hussain",

@@ -37,3 +37,7 @@ "license": "MIT",

"docs",
"docs/migration-gitpin.md"
"docs/migration-gitpin.md",
"action.yml",
"scripts/render-gate-action-report.mjs",
"templates/gate.yml",
"templates/change-evidence.json"
],

@@ -102,2 +106,5 @@ "publishConfig": {

"provenance",
"pull-request",
"ci",
"ai-governance",
"claude-code",

@@ -104,0 +111,0 @@ "codex",

@@ -9,5 +9,5 @@ # GitPin

### Pin agent answers to Git HEAD. Path. Line. Full SHA. Prove. Verify.
### Make agent-authored changes show exact evidence before merge.
**GitPin is not another “repo context” MCP.** That category is full of vector indexes, dump files, and remote GitHub browsers. GitPin is a **trust product**: index-free, read-only, multi-repo **evidence** agents must prove and humans can re-check with `git show`.
**GitPin is an agent-delivery assurance gate with a local evidence MCP.** It makes material PR claims cover the actual diff and point to exact committed line slices. The local MCP supplies index-free, read-only, multi-repo evidence that humans and CI can re-check with `git show`.

@@ -32,2 +32,10 @@ ```text

## Required PR evidence gate
```bash
gitpin gate --base <full-base-sha> --head <full-head-sha>
```
The gate reads policy only from the trusted base commit, reads the submitted manifest only from the head commit, compares the merge-base diff, and verifies exact line-slice hashes. It never executes PR code and never labels a locator match as proof of semantic correctness. Use the [GitHub Action and CrewScore named-control setup](docs/pr-evidence-gate.md) as a required check.
> **Release:** publish a version-matched GitPin release across npm, the MCP Registry, GitHub, and Pages before announcing. Install: `npx -y gitpin@latest`. Node 20+.

@@ -34,0 +42,0 @@

@@ -7,2 +7,4 @@ # Roadmap

- Read-only `gitpin gate` for base-trusted PR policy, changed-path coverage, and exact-commit evidence locators.
- GitHub Action that emits a deterministic report suitable for a required merge check.
- Twelve bounded, read-only `pin.*` MCP tools for discovery, evidence, verification, and decision support.

@@ -26,2 +28,4 @@ - Git `HEAD` pinning with path, line, content hash, and full commit provenance.

- Run the PR gate on real agent-authored changes and measure required-check retention, false blocking, and review decisions changed.
- Validate CrewScore named controls as a separate written-policy check without using its aggregate coverage score.
- Validate EvidenceBrief usefulness with technical and cross-functional users using synthetic fixtures.

@@ -28,0 +32,0 @@ - Improve fixtures for workspace repositories, stale documentation, malformed policies, and remote snapshots.

@@ -10,3 +10,3 @@ {

},
"version": "0.5.3",
"version": "0.6.0",
"packages": [

@@ -16,3 +16,3 @@ {

"identifier": "gitpin",
"version": "0.5.3",
"version": "0.6.0",
"transport": {

@@ -19,0 +19,0 @@ "type": "stdio"

@@ -13,2 +13,2 @@ # GitPin client rules (paste into AGENTS.md / Cursor rules / Claude project)

Install: `npx -y gitpin@0.5.3` and set `GITPIN_REGISTRY`.
Install: `npx -y gitpin@0.6.0` and set `GITPIN_REGISTRY`.