Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
cc16ce3
Add analysis foundations for parsers, graphs, and diff artifacts
alxxjohn Jun 11, 2026
7578b5f
Add TypeScript untrusted input flow detection
alxxjohn Jun 11, 2026
16a2d94
Add clone, test-quality, and performance checks
alxxjohn Jun 11, 2026
4183f50
Move analysis tests into tests and reduce warning noise
alxxjohn Jun 11, 2026
731a3b7
Refactor analysis helpers to reduce code quality noise
alxxjohn Jun 11, 2026
1d3ee50
Reduce remaining scanner warning noise
alxxjohn Jun 11, 2026
e5fedfa
save
alxxjohn Jun 11, 2026
76f8031
save
alxxjohn Jun 11, 2026
35d06e5
hooks-actions
alxxjohn Jun 11, 2026
bd72e3f
sav3
alxxjohn Jun 12, 2026
e65a118
save
alxxjohn Jun 12, 2026
4de360e
save
alxxjohn Jun 12, 2026
00ff0a7
save
alxxjohn Jun 12, 2026
04331b4
save
alxxjohn Jun 12, 2026
d8fc21c
feat(typescript): cross-module taint analysis with function summaries
alxxjohn Jun 12, 2026
1406bd5
feat: add contracts check family for API/contract drift detection
alxxjohn Jun 12, 2026
29f8536
Add cross-language dependency graphs and performance smell rules
alxxjohn Jun 12, 2026
9a1b84b
Add Anthropic provider, HTTP retry, NL-rule verdict cache, and fix te…
alxxjohn Jun 12, 2026
f7b0ae2
Add coverage-delta gating and test assertion-quality rules
alxxjohn Jun 12, 2026
f168029
Complete AI-quality pack: Python imports, dead code, drift checks, sl…
alxxjohn Jun 12, 2026
410f5ea
Untrack generated test cache artifacts and ignore slop-history files
alxxjohn Jun 12, 2026
9f42f4a
feat(parsers,security): deepen pure-Go parsers and add Go/Python tain…
alxxjohn Jun 12, 2026
30fa959
Merge feat/ai-quality-complete: Python hallucinated imports, dead-cod…
alxxjohn Jun 12, 2026
6bee7bc
Merge feat/llm-infra: Anthropic provider, HTTP retry, NL-rule verdict…
alxxjohn Jun 12, 2026
82a47d3
Fix anthropic triage fixture: export BuildClient so dead-code rule do…
alxxjohn Jun 12, 2026
1604578
Merge feat/contract-drift: contracts check family (Go API, OpenAPI, p…
alxxjohn Jun 12, 2026
357bf06
Merge feat/coverage-delta: coverage-delta gating + hardened test-qual…
alxxjohn Jun 12, 2026
7ec15e7
Merge feat/graphs-perf: multi-language import graphs, god-module, cha…
alxxjohn Jun 12, 2026
abb630e
Merge feat/parsers-taint: structured pure-Go parsers (Python + C-like…
alxxjohn Jun 12, 2026
f501c95
Merge feat/ts-crossfile-taint: cross-module TypeScript taint via func…
alxxjohn Jun 12, 2026
2d56fd1
Post-merge polish: split oversized dead-code file, exclude .claude fr…
alxxjohn Jun 12, 2026
daa7d27
Fix all codeguard-ci warnings: tune noisy rules, dedupe real clones, …
alxxjohn Jun 12, 2026
f5fffef
Add local-dev knowledge: GOROOT workaround, scan-cache gotchas
alxxjohn Jun 12, 2026
d8fc0f9
chore(release): align public release automation
alxxjohn Jun 16, 2026
f7cc9cd
feat(inital release): initial release
alxxjohn Jun 16, 2026
b6620e3
feat: feat(inital release)
alxxjohn Jun 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
7 changes: 7 additions & 0 deletions .claude/knowledge/local-dev-setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Local Development Setup

How to set up, run, and work with this project locally. Non-obvious dependencies, environment config, common setup issues.

- This machine has a stale `GOROOT=/Users/alex/apps/go` env var that breaks the homebrew Go toolchain. Run go commands as `env -u GOROOT go ...` (build, test, vet, gofmt).
- When iterating on check/rule logic, delete `.codeguard/cache.json` before self-scanning (`make codeguard-ci`). The scan cache keys on file hash + config hash but NOT the codeguard binary version, so rule-logic changes replay stale per-file findings — cross-file analyses (duplicate-code, import graphs) can appear to report zero findings when they're actually being skipped.
- Cross-file checks (clone detection, dependency graphs) only observe every file via `VisitTargetFiles` (cache-bypassing); `ScanTargetFiles` skips evaluators on cache hits and silently produces empty cross-file state on a second scan.
15 changes: 14 additions & 1 deletion .codeguard/codeguard.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
name: codeguard-repo-ci
exclude:
- .claude/**
- .codeguard/cache.json
- .codeguard/cache.slop-history.json
- .gomodcache/**
- tests/**/.codeguard/cache.json
waivers:
- rule: quality.max-file-lines
path: internal/codeguard/rules/catalog_quality.go
reason: rule catalog is intentionally dense and should still be scanned by other checks
- rule: quality.max-file-lines
path: tests/checks/features_test.go
reason: consolidated feature coverage is intentionally broad and should still be scanned by other checks
targets:
- name: repository
path: .
path: ..
language: go
entrypoints:
- cmd/codeguard
Expand Down
97 changes: 97 additions & 0 deletions .github/workflows/homebrew-validation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
name: homebrew-validation.yml

on:
pull_request:
branches:
- develop
- master
- main

permissions:
contents: read

jobs:
formula-validation:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- macos-latest

steps:
- name: Check out code
uses: actions/checkout@v6

- name: Set up Homebrew
uses: Homebrew/actions/setup-homebrew@main

- name: Clone Homebrew tap
shell: bash
env:
TAP_REPOSITORY: devr-tools/homebrew-tap
run: |
set -euo pipefail
git clone --depth 1 "https://github.com/${TAP_REPOSITORY}.git" "$RUNNER_TEMP/homebrew-tap"

- name: Patch tap formula for current checkout
shell: bash
run: |
set -euo pipefail

version="$(awk -F'"' '/^const Number = / { print $2; exit }' internal/version/version.go)"
archive_path="$RUNNER_TEMP/codeguard-src.tar.gz"
tap_dir="$RUNNER_TEMP/homebrew-tap"
formula_path="$RUNNER_TEMP/homebrew-tap/Formula/codeguard.rb"
git archive --format=tar.gz --output "$archive_path" HEAD
sha256="$(shasum -a 256 "$archive_path" | awk '{print $1}')"

if [ -z "$version" ]; then
echo "failed to extract codeguard version from internal/version/version.go"
exit 1
fi

cat > "$formula_path" <<EOF
class Codeguard < Formula
desc "Repository policy and AI code review CLI for CI"
homepage "https://github.com/devr-tools/codeguard"
url "file://$archive_path"
sha256 "$sha256"
version "$version"
license "Apache-2.0"
depends_on "go" => :build

def install
ldflags = "-s -w -X github.com/devr-tools/codeguard/internal/version.Number=v#{version}"
system "go", "build", *std_go_args(output: bin/"codeguard", ldflags: ldflags), "./cmd/codeguard"
end

test do
assert_match version.to_s, shell_output("#{bin}/codeguard version")
end
end
EOF

git -C "$tap_dir" config user.name "github-actions[bot]"
git -C "$tap_dir" config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git -C "$tap_dir" add Formula/codeguard.rb
git -C "$tap_dir" commit -m "test: patch codeguard formula for validation"

- name: Tap current formula checkout
shell: bash
run: |
set -euo pipefail
brew tap devr-tools/tap "$RUNNER_TEMP/homebrew-tap"

- name: Build formula from source
shell: bash
run: |
set -euo pipefail
HOMEBREW_NO_AUTO_UPDATE=1 brew install --build-from-source devr-tools/tap/codeguard

- name: Run formula test
shell: bash
run: |
set -euo pipefail
brew test devr-tools/tap/codeguard
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Upload release bundle
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: dist-${{ steps.release.outputs.tag }}
path: dist/*
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ go.work.sum
# Editor/IDE
.idea/
.vscode/
**/.codeguard/cache.slop-history.json
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

`codeguard` is a standalone Go service and CLI for repository checks across code quality, design boundaries, security, CI/CD hygiene, AI prompt governance, and repo-specific policy rules.

It now supports repository exclusions, baselines, waivers, changed-lines diff scans, SARIF output, GitHub annotations, custom rule packs, policy profiles, scan caching, doctor checks, rule discovery from the CLI, native TypeScript/Python quality, design, and security heuristics, and language-specific command checks.
It now supports repository exclusions, baselines, waivers, changed-lines diff scans, SARIF output, GitHub annotations, custom rule packs, natural-language custom rules through an optional AI runtime, policy profiles, scan caching, doctor checks, rule discovery from the CLI, native TypeScript/Python quality, design, and security heuristics, and language-specific command checks.

AI-generated-code quality coverage includes an AI-failure-mode rule pack, `slop_score` artifacts, provenance-aware review policy hooks, local idiom drift checks, optional provider-backed hybrid triage and semantic review passes, natural-language custom rules through an optional AI runtime, and a verified-fix flow that only returns patches after isolated patch validation plus test reruns succeed.

The public Go SDK lives at `github.com/devr-tools/codeguard/pkg/codeguard`.

Expand All @@ -23,6 +25,11 @@ Or build from source:
make build
```

Other install paths:

- GitHub Releases: tagged archives for direct download
- Homebrew: `brew install devr-tools/tap/codeguard`

Or run in Docker:

```bash
Expand All @@ -39,7 +46,7 @@ make release-check
make deploy
```

The GitHub release flow follows the same branch and release-please model as `cleanr`, using `.github/workflows/cd.yml`, `.github/workflows/release.yml`, `.github/release-please-config.json`, and `.release-please-manifest.json`.
The GitHub release flow follows the same branch and release-please model as `cleanr`, using `.github/workflows/cd.yml`, `.github/workflows/release.yml`, `.github/workflows/homebrew-validation.yml`, `.github/release-please-config.json`, and `.release-please-manifest.json`.

For SDK consumers:

Expand Down Expand Up @@ -96,7 +103,12 @@ func main() {
## Docs

- [Getting started](/Users/alex/Documents/GitHub/codeguard/docs/getting-started.md:1)
- [AI-generated code quality](/Users/alex/Documents/GitHub/codeguard/docs/ai-quality.md:1)
- [Agent-native features](/Users/alex/Documents/GitHub/codeguard/docs/agent-native.md:1)
- [Integrations](/Users/alex/Documents/GitHub/codeguard/docs/integrations.md:1)
- [Hook-pack examples](/Users/alex/Documents/GitHub/codeguard/examples/hooks/README.md:1)
- [SDK guide](/Users/alex/Documents/GitHub/codeguard/docs/sdk.md:1)
- [Release automation](/Users/alex/Documents/GitHub/codeguard/docs/release-automation.md:1)
- [Homebrew packaging](/Users/alex/Documents/GitHub/codeguard/docs/homebrew.md:1)
- [Checks reference](/Users/alex/Documents/GitHub/codeguard/docs/checks.md:1)
- [Architecture](/Users/alex/Documents/GitHub/codeguard/docs/architecture.md:1)
69 changes: 63 additions & 6 deletions action.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
name: codeguard
description: Run CodeGuard repository policy checks
name: Devr Codeguard
description: Run Devr CodeGuard repository policy checks for AI generated and human code
branding:
icon: shield
color: gray-dark


inputs:
config:
description: Path to the CodeGuard config file
description: Path to the Devr CodeGuard config file
required: false
default: codeguard.yaml
profile:
Expand All @@ -22,8 +26,16 @@ inputs:
description: Output format
required: false
default: github
comment-fix-mode:
description: PR comment mode. Use sticky to create or update a fix-oriented PR comment.
required: false
default: "off"
comment-tag:
description: Sticky marker used to update an existing CodeGuard PR comment.
required: false
default: codeguard-action-comment
version:
description: CodeGuard version to install
description: Devr CodeGuard version to install
required: false
default: latest

Expand All @@ -35,24 +47,69 @@ runs:
with:
go-version: "1.23"

- name: Install CodeGuard
- name: Install Devr CodeGuard
shell: bash
run: go install github.com/devr-tools/codeguard/cmd/codeguard@${{ inputs.version }}

- name: Run CodeGuard
- name: Run Devr CodeGuard
id: scan
shell: bash
run: |
set +e
if [ -n "${{ inputs.profile }}" ]; then
codeguard scan \
-config "${{ inputs.config }}" \
-mode "${{ inputs.mode }}" \
-base-ref "${{ inputs.base-ref }}" \
-format "${{ inputs.format }}" \
-profile "${{ inputs.profile }}"
status=$?
else
codeguard scan \
-config "${{ inputs.config }}" \
-mode "${{ inputs.mode }}" \
-base-ref "${{ inputs.base-ref }}" \
-format "${{ inputs.format }}"
status=$?
fi
echo "exit_code=$status" >> "$GITHUB_OUTPUT"
exit 0

- name: Post Devr CodeGuard fix comment
if: ${{ inputs.comment-fix-mode != 'off' && (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') }}
shell: bash
working-directory: ${{ github.action_path }}
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
report_file="$(mktemp)"
set +e
if [ -n "${{ inputs.profile }}" ]; then
codeguard scan \
-config "${{ inputs.config }}" \
-mode "${{ inputs.mode }}" \
-base-ref "${{ inputs.base-ref }}" \
-format github-comment \
-profile "${{ inputs.profile }}" > "$report_file"
else
codeguard scan \
-config "${{ inputs.config }}" \
-mode "${{ inputs.mode }}" \
-base-ref "${{ inputs.base-ref }}" \
-format github-comment > "$report_file"
fi
set -e
if [ ! -s "$report_file" ]; then
echo "CodeGuard comment report was empty; skipping comment publish."
exit 0
fi
go run ./cmd/codeguard-action-comment \
-body-file "$report_file" \
-repository "${{ github.repository }}" \
-marker "${{ inputs.comment-tag }}" \
-mode "${{ inputs.comment-fix-mode }}"

- name: Fail workflow on Devr CodeGuard findings
if: ${{ steps.scan.outputs.exit_code != '0' }}
shell: bash
run: exit "${{ steps.scan.outputs.exit_code }}"
71 changes: 71 additions & 0 deletions cmd/codeguard-action-comment/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package main

import (
"flag"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"strings"

"github.com/devr-tools/codeguard/internal/githubaction"
)

func main() {
os.Exit(run(os.Args[1:], os.Stdout, os.Stderr))
}

func run(args []string, stdout io.Writer, stderr io.Writer) int {
fs := flag.NewFlagSet("codeguard-action-comment", flag.ContinueOnError)
fs.SetOutput(stderr)
bodyFile := fs.String("body-file", "", "path to markdown body file")
eventPath := fs.String("event-path", os.Getenv("GITHUB_EVENT_PATH"), "path to the GitHub event payload")
repository := fs.String("repository", os.Getenv("GITHUB_REPOSITORY"), "repository in owner/name format")
token := fs.String("token", os.Getenv("GITHUB_TOKEN"), "GitHub token")
apiURL := fs.String("api-url", os.Getenv("GITHUB_API_URL"), "GitHub API base URL")
marker := fs.String("marker", "codeguard-action-comment", "sticky comment marker")
mode := fs.String("mode", "sticky", "comment mode: sticky or new")
if err := fs.Parse(args); err != nil {
return 1
}

if strings.TrimSpace(*bodyFile) == "" {
_, _ = fmt.Fprintln(stderr, "body-file is required")
return 1
}
if strings.TrimSpace(*repository) == "" {
_, _ = fmt.Fprintln(stderr, "repository is required")
return 1
}
if strings.TrimSpace(*token) == "" {
_, _ = fmt.Fprintln(stderr, "token is required")
return 1
}

body, err := os.ReadFile(filepath.Clean(*bodyFile))
if err != nil {
_, _ = fmt.Fprintf(stderr, "read body file: %v\n", err)
return 1
}
prNumber, err := githubaction.ResolvePullRequestNumber(*eventPath)
if err != nil {
_, _ = fmt.Fprintf(stderr, "resolve pull request number: %v\n", err)
return 1
}

commentBody := githubaction.WrapCommentBody(string(body), *marker)
client := githubaction.CommentPublisher{
BaseURL: githubaction.NormalizeAPIURL(*apiURL),
Token: strings.TrimSpace(*token),
Client: http.DefaultClient,
}

if err := client.Publish(*repository, prNumber, commentBody, strings.TrimSpace(*mode)); err != nil {
_, _ = fmt.Fprintf(stderr, "publish comment: %v\n", err)
return 1
}

_, _ = fmt.Fprintf(stdout, "published CodeGuard PR comment on #%d\n", prNumber)
return 0
}
5 changes: 5 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
# CodeGuard Docs

- [Getting started](getting-started.md)
- [AI-generated code quality](ai-quality.md)
- [Agent-native features](agent-native.md)
- [Integrations](integrations.md)
- [Hook-pack examples](../examples/hooks/README.md)
- [SDK guide](sdk.md)
- [Release automation](release-automation.md)
- [Homebrew packaging](homebrew.md)
- [Architecture](architecture.md)
- [Checks](checks.md)
Loading
Loading