audit-repo README

The project's README from github.com/1838904818/audit-repo. As one markdown file: README.md.

audit-repo

CI Release Latest release License: MIT

An evidence-backed, read-only repository health audit Skill for Codex, with standalone Python tools for reproducible inventory and snapshot comparison.

中文简介:这是一个实用的 Codex Skill,用于只读审查代码仓库的测试、CI、依赖、文档、安全信号与技术债,并将结果整理为有证据和优先级的行动清单。参见中文快速开始。

Features

The collector produces inventory signals, not automatic findings. The Skill tells Codex to verify context and evidence before assigning impact or priority.

Install as a Codex Skill

The easiest option in Codex is to ask the built-in installer to install this repository:

Use $skill-installer to install https://github.com/1838904818/audit-repo.

For an offline or version-pinned installation, download the .zip and matching .sha256 file from the latest release. Verify the checksum, then extract the archive's top-level audit-repo directory into $HOME/.agents/skills. Release assets are built only after the full test matrix passes on Linux, Windows, and macOS with Python 3.10 and 3.14. Before repository code runs, publishing verifies that the remote tag resolves to the workflow event commit on the default branch. It then requires the published Release to be immutable, verifies that its exact two-asset set matches the current deterministic build, and rechecks tag/default-branch provenance after the online assets match. A run that finds an existing published Release leaves it unchanged and verifies it; an existing draft fails closed without being edited or deleted. Immutability applies to v1.10.7 and later releases, not historical releases created before the repository setting was enabled.

For a manual user-wide installation, clone the repository into the official local skills directory. See the OpenAI Build skills documentation for current locations and invocation methods.

macOS or Linux:

mkdir -p "$HOME/.agents/skills"
git clone https://github.com/1838904818/audit-repo.git "$HOME/.agents/skills/audit-repo"

Windows PowerShell:

$skillRoot = Join-Path $HOME ".agents\skills"
New-Item -ItemType Directory -Force -Path $skillRoot | Out-Null
git clone https://github.com/1838904818/audit-repo.git (Join-Path $skillRoot "audit-repo")

Codex detects installed skill changes automatically. If the Skill does not appear, restart Codex.

Invoke it explicitly in Codex CLI or the IDE extension with /skills or $audit-repo:

Use $audit-repo to audit this repository and prioritize the most important fixes.

In the ChatGPT desktop app, type @ and choose Audit Repo from the skill picker.

Codex can also invoke it automatically for repository health, release readiness, maintainability, security posture, technical debt, and audit comparison requests.

Standalone usage

Requires Python 3.10 or newer. Python 3.10 through 3.14 are continuously tested, and the scripts use only the Python standard library.

Audit a repository:

python scripts/collect_repo_signals.py /path/to/repo --format markdown

Save a reusable JSON snapshot:

python scripts/collect_repo_signals.py /path/to/repo --format json --output before.json

When using filesystem, keep reusable snapshots outside the target repository so an earlier output does not become input to the next scan.

Choose a scan mode for the intended workflow:

# Default: reachable filesystem files, including ignored and untracked files
python scripts/collect_repo_signals.py /path/to/repo --scan-mode filesystem

# Tracked files plus non-ignored untracked files
python scripts/collect_repo_signals.py /path/to/repo --scan-mode git-visible

# Stable CI baseline containing tracked files that are present in the worktree
python scripts/collect_repo_signals.py /path/to/repo --scan-mode tracked --scope-id acme/widget:whole-repository

Scope a monorepo with repeatable, case-sensitive, root-relative POSIX globs:

python scripts/collect_repo_signals.py /path/to/repo \
  --scan-mode tracked \
  --include-path "packages/api/*" \
  --exclude-path "packages/api/generated/*" \
  --scope-id acme/widget:api-package \
  --format json --output api.json

Every mode keeps the collector's built-in directory exclusions and skips symlinks. Path globs use Python fnmatchcase semantics against the full relative path; * can match /, and exclusions win over inclusions. tracked omits every untracked file, whether ignored or not, but still includes tracked files that later match an ignore rule. Use filesystem when discovering accidentally created sensitive files is the priority.

git-visible follows the checkout's effective Git ignore configuration, including repository-local and global excludes. Use the same ignore configuration for repeat comparisons. Git metadata such as worktree state describes the Git checkout and can be broader than a path-glob scope. If Git enumerates a tracked file that is absent from the worktree—for example in a sparse checkout—the snapshot records an incomplete scan and the comparer will not treat it as directly comparable.

Scope IDs are unset by default and do not change which files are scanned. They are only an explicit assertion that snapshots from different resolved roots represent the same logical scope. Use a project-qualified value on both snapshots, never reuse it across repositories or packages, and regenerate a reviewed baseline when adopting it. The legacy implicit value repository no longer proves cross-root equivalence.

v1.9.0 also advances scan semantics to version 2. Snapshots created by v1.8.x therefore produce a deliberate comparison limitation even at the same root; review the new classification rules and regenerate approved baselines before restoring a comparability gate.

v1.9.1 advances scan semantics to version 3 because Windows junction and reparse-point traversal is now excluded consistently with symbolic links. A v1.9.0 baseline therefore produces a deliberate limitation; review the boundary change and regenerate the approved baseline before restoring --require-comparable.

Manifest and lockfile inventory uses canonical, case-sensitive filenames so a snapshot does not claim that an ecosystem tool will consume a mis-cased file on a case-sensitive platform. The inventory includes SwiftPM version-specific manifests and NuGet project-specific lockfiles. GitHub Action references are lexical workflow signals: script and description block contents are excluded, while an unambiguous single-line block value attached to uses is recognized. A pinning policy must fail closed on YAML anchors, aliases, tags, and explicit mapping-key syntax that can make a parsed dependency key differ from a simple textual search.

Compare two snapshots:

python scripts/compare_repo_signals.py before.json after.json --format markdown

Run the complete workflow with one command. It always writes snapshot.json and report.md; when a baseline is supplied it also writes comparison.json and comparison.sarif:

python scripts/check_repo.py /path/to/repo --output-dir audit-results
python scripts/check_repo.py /path/to/repo \
  --baseline previous-snapshot.json \
  --baseline-sha256 "$EXPECTED_BASELINE_SHA256" \
  --output-dir audit-results \
  --fail-on-attention --require-comparable

--baseline-sha256 accepts exactly 64 hexadecimal characters (uppercase or lowercase) and checks the baseline's raw bytes before parsing it. Prefixes, whitespace, and checksum-file lines are rejected. JSON formatting, a byte-order mark, trailing newlines, and LF/CRLF conversion all change the digest. External snapshots and baselines must resolve to regular files no larger than 64 MiB; pipes, devices, directories, and larger files are rejected. A symbolic link remains accepted when its opened target is a regular file within that limit. Snapshot JSON must also have unique object keys at every nesting level; duplicate keys are rejected because JSON consumers disagree on first-value versus last-value interpretation. Obtain the expected digest independently from maintainer-controlled configuration or a separately verified artifact; do not calculate it from the same untrusted baseline immediately before this check.

Before each run, the runner removes only those four managed output paths so reused directories cannot expose stale reports. It preflights all four paths, preserves every other entry, and fails with exit code 2 without deleting any sibling artifact when a managed path is a directory. Enabling either comparison gate without --baseline is also invalid. A malformed digest, digest without a baseline, digest mismatch, unreadable, oversized, non-regular, or invalid baseline fails before the output directory is created or any managed artifact or GitHub Action output is changed. When supplied, the baseline is opened once, verified as a bounded regular file, read once, optionally digest-checked, parsed as strict UTF-8 JSON, and kept in memory for the comparison. The digest remains optional; valid, unchanged baselines retain the same comparison semantics and results when it is omitted, although the runner still reads and freezes the baseline before collection. Snapshot, scan-root, and managed-output path context is ASCII-escaped and length-bounded in errors so hostile filenames cannot add CI log lines or workflow commands.

The runner also validates --max-files, --large-file-mib, include/exclude path globs, excluded directory names, --scope-id, scan-root availability, and Git-mode worktree eligibility before it creates or clears managed output, allocates an Action temporary directory, or appends Action outputs. An excluded directory must be a non-empty single name: path separators, ./.., whitespace-only values, and control characters are rejected, while names beginning with - remain valid. Matching is case-insensitive, as in earlier releases. The collector and runner share those preflight rules, so malformed settings, a missing root, or an incompatible Git scan mode returns 2 without sacrificing earlier reports. Successful collection still occurs after stale managed files are cleared, preserving established scan results when the output directory is inside the scanned root.

The runner also refuses an output directory that traverses a symbolic link or Windows reparse point (including an NTFS junction) anywhere inside the scanned repository or its containing Git worktree. This includes monorepo siblings when only a subdirectory is scanned, preventing an untrusted checkout from redirecting managed writes outside its tree. In Action mode, the GitHub output file must not equal or alias the baseline or any managed artifact.

Git-aware collection resolves Git to an absolute executable found in an absolute PATH directory outside the entire containing Git worktree, including when only a monorepo subdirectory is scanned. Both the lexical scan entry and its resolved target define untrusted boundaries, and containment is verified by filesystem identity as well as path spelling. Repository-contained symlinks or case variants on case-insensitive volumes therefore cannot hide a checkout-local executable. The collector never relies on current-directory executable lookup, so a checkout-local git.exe cannot turn a static Windows audit into code execution. Worktree cleanliness is intentionally reported as unknown so the inventory does not invoke broader repository-aware status machinery.

Run an audit against a quiescent checkout and do not execute untrusted repository code concurrently. Collection is a point-in-time best effort across multiple filesystem operations; a separate process that replaces files during the scan can invalidate earlier link, identity, or size observations. Use an isolated checkout when concurrent writers cannot be excluded.

Use snapshot comparison in automation, failing both on high-confidence attention items and on an incomparable baseline:

python scripts/compare_repo_signals.py before.json after.json --fail-on-attention --require-comparable

Produce SARIF 2.1.0 for code-scanning viewers and CI systems:

python scripts/compare_repo_signals.py before.json after.json \
  --format sarif --output audit-repo.sarif

SARIF warning results are attention signals and note results are comparison limitations. They require repository-context verification and are not confirmed vulnerabilities. Policy exit codes remain controlled separately by --fail-on-attention and --require-comparable.

Comparison exit codes:

New JSON snapshots record the collector version, scan-semantics version, mode, logical path scope, configured file limit, scan completeness, and every large file found within the scanned scope. Comparison JSON, Markdown, and SARIF preserve both snapshots' provenance so compatibility decisions remain visible in every report format. A collector release can change without invalidating comparisons when its scan semantics remain compatible; a changed or one-sided semantics version becomes a comparison limitation and suppresses scope-dependent alerts. Two legacy snapshots without this metadata remain mutually comparable under the older rules. Markdown output displays at most 20 items per long change list and points to JSON for the complete data. A project-qualified non-empty --scope-id lets equivalent checkouts at different absolute roots compare safely. When an older snapshot may contain only the legacy top-20 large-file list, the comparer reports a limitation and suppresses unreliable large-file addition/removal alerts.

Run python scripts/collect_repo_signals.py --help or python scripts/compare_repo_signals.py --help for all options.

GitHub Actions

Use the repository directly as a composite Action. Pin a release tag or commit SHA in production workflows:

- uses: 1838904818/[email protected]
  id: audit
  with:
    scan-mode: tracked
    scope-id: ${{ github.repository }}:whole-repository
    output-dir: ${{ runner.temp }}/audit-repo

The Action requires Python 3.10 or newer on the runner and does not install project dependencies. It starts Python in isolated mode so checkout-local modules cannot shadow the standard library. When output-dir is omitted, it creates a unique directory under GitHub's RUNNER_TEMP instead of writing into the audited checkout. Its outputs include snapshot, report, comparison, sarif, attention-count, comparable, tool-version, and scan-semantics-version; callers can upload reports or record provenance without parsing the snapshot.

For a checked-in baseline, enable both policy gates:

- name: Validate baseline digest configuration
  shell: bash
  env:
    EXPECTED_BASELINE_SHA256: ${{ vars.AUDIT_BASELINE_SHA256 }}
  run: |
    [[ "$EXPECTED_BASELINE_SHA256" =~ ^[0-9A-Fa-f]{64}$ ]] || {
      echo "::error::AUDIT_BASELINE_SHA256 must be configured as exactly 64 hex characters"
      exit 2
    }

- uses: 1838904818/[email protected]
  with:
    baseline: .github/audit-baseline.json
    baseline-sha256: ${{ vars.AUDIT_BASELINE_SHA256 }}
    scan-mode: tracked
    scope-id: ${{ github.repository }}:whole-repository
    exclude-paths: |
      .github/audit-baseline.json
    fail-on-attention: "true"
    require-comparable: "true"

include-paths, exclude-paths, and exclude-dirs accept LF- or CRLF-separated values. The Action removes only the trailing CR introduced by a CRLF line ending; embedded control characters remain invalid. Each non-empty exclude-dirs line is one directory name, not a path; the Action safely preserves a leading - in that name. Create the approved baseline with the same exclusions so the baseline file does not become part of its own comparison scope. Configure the non-secret digest variable through maintainer-controlled repository or environment settings, and keep the explicit format check: an unset Actions variable expands to an empty value, which otherwise means no digest pin was requested. Policy inputs accept only the exact strings true and false. Leave both gates false for a collection-only run: enabling either gate without baseline, or supplying another boolean spelling, is rejected as invalid configuration instead of silently disabling policy.

Digest matching proves only that the baseline has the expected exact bytes. It does not prove authorship, freshness, review status, safety, unambiguous JSON semantics, or comparison compatibility, and it does not replace strict parsing or require-comparable. In a pull_request workflow, a baseline and digest both loaded from the untrusted pull-request checkout—or a digest calculated from that baseline in the same job—do not form an independent security gate. Load the baseline from a protected base ref or separately trusted artifact, obtain its expected digest through an independent maintainer-controlled channel, and verify both before comparison.

What the audit covers

Area Example signals
Repository state Git repository, branch or detached commit, tracked file count; worktree cleanliness remains safely unknown
Build and dependencies Manifests, lockfiles, configured tools, package scripts, Make targets
Verification Tests, CI configuration, CI action references
Security hygiene Sensitive-looking filenames, environment examples, dependency update configuration
Maintainability TODO/FIXME-style comment markers, documentation, ownership, policies
Delivery Container files, large files, license files

See SKILL.md for the agent workflow, audit rubric for priorities, and check selection for safe project-native commands.

Project resources

audit-repo (1838904818/audit-repo)

Searching Database…

Что это такое?Codex Skill для проверки здоровья кодовых репозиториев в режиме только чтения и с опорой на доказательства: он инвентаризирует тесты, CI, зависимости, документацию, сигналы безопасности и технический долг, а затем превращает проверенные находки в приоритизированный список действий. В комплекте идут автономные Python-скрипты для воспроизводимых снимков состояния.
Он работает внутри Codex или можно пользоваться им отдельно?И так, и так. Установите его как Codex Skill, чтобы Codex проводил аудиты в режиме пошагового сопровождения, либо запускайте автономные Python-скрипты напрямую, чтобы собирать снимки инвентаря и сравнивать их — Codex для этого не нужен.
Что нужно для автономных скриптов?Только Python 3.10 или новее (непрерывно тестируются версии с 3.10 по 3.14); скрипты используют лишь стандартную библиотеку, поэтому ничего через pip ставить не нужно, и зависимости проверяемого проекта тоже никогда не устанавливаются.
Он просто скажет мне, что не так с моим репозиторием?Никаких вердиктов: сборщик выдаёт только сигналы инвентаря, а Skill предписывает Codex проверять контекст и доказательства, прежде чем назначать влияние или приоритет. Пункты внимания — это сигналы для ревью, а не подтверждённые уязвимости.
В моих репозиториях есть секреты — не утечут ли они при аудите?Нет. Проверки по дизайну работают на уровне имён файлов и никогда не читают и не печатают содержимое чувствительных файлов, поэтому снимки и отчёты свободны от значений секретов.
Как его вызвать после установки?В Codex CLI или IDE-расширении вызовите его через /skills или $audit-repo; в десктопном приложении ChatGPT введите @ и выберите Audit Repo. Codex также может вызывать его автоматически по запросам о здоровье репозитория, готовности к релизу, сопровождаемости, безопасности или техническом долге.
Какие типы проектов он распознаёт?Он определяет состояние Git, манифесты, lock-файлы, тесты, CI, автоматизацию, владение кодом, контейнеры, признаки активности, крупные файлы и подозрительные имена файлов в типичных репозиториях на Python, JavaScript, .NET, Swift, JVM, Go, Rust, Ruby и PHP.
Может ли он отслеживать здоровье во времени и ломать CI при регрессиях?Да. Одна команда записывает snapshot.json и report.md, а при наличии базовой версии ещё и comparison.json и comparison.sarif. Шлюзы вроде --fail-on-attention и --require-comparable завершаются с кодом 1 при неудаче (с кодом 2 при некорректных входных данных), а вывод в формате SARIF 2.1.0 подключается к просмотрщикам code scanning.
Почему такой упор на неизменяемые релизы и контрольные суммы базовой версии?Это защита цепочки поставок: релизные артефакты собираются только после прохождения полной матрицы тестов на Linux, Windows и macOS с Python 3.10 и 3.14, релизы начиная с v1.10.7 неизменяемы, а --baseline-sha256 фиксирует точный 64-значный hex-дайджест байтов базовой версии до того, как что-либо будет разобрано.
Creator
1838904818
Size
0.7 MB
Stars
157
Age
2mo
Commits · 90 Days