Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 6 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ jobs:
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Clone hawk for shared/types
run: git clone --depth=1 https://github.com/GrayCodeAI/hawk.git ../hawk
- name: Boundary guard
run: bash ./scripts/check-ecosystem-boundaries.sh
- name: gofumpt diff
run: |
go install mvdan.cc/gofumpt@v0.10.0
Expand All @@ -77,8 +77,8 @@ jobs:
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Clone hawk for shared/types
run: git clone --depth=1 https://github.com/GrayCodeAI/hawk.git ../hawk
- name: Boundary guard
run: bash ./scripts/check-ecosystem-boundaries.sh
- uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v7.0.0
with:
version: v2.1.0
Expand All @@ -98,8 +98,8 @@ jobs:
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Clone hawk for shared/types
run: git clone --depth=1 https://github.com/GrayCodeAI/hawk.git ../hawk
- name: Boundary guard
run: bash ./scripts/check-ecosystem-boundaries.sh
- name: Tidy check
run: |
go mod tidy
Expand Down Expand Up @@ -139,8 +139,6 @@ jobs:
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Clone hawk for shared/types
run: git clone --depth=1 https://github.com/GrayCodeAI/hawk.git ../hawk
- name: govulncheck
run: |
go install golang.org/x/vuln/cmd/govulncheck@v1.1.4
Expand All @@ -165,8 +163,6 @@ jobs:
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Clone hawk for shared/types
run: git clone --depth=1 https://github.com/GrayCodeAI/hawk.git ../hawk
- name: deadcode
run: |
go install golang.org/x/tools/cmd/deadcode@latest
Expand Down Expand Up @@ -210,8 +206,6 @@ jobs:
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Clone hawk for shared/types
run: git clone --depth=1 https://github.com/GrayCodeAI/hawk.git ../hawk
- name: Build
env:
GOOS: ${{ matrix.goos }}
Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ basic
# Local state
.claude/
.codegraph/
.gocache/
coverage.out

# Go workspace (local dev only — each developer creates their own)
go.work
go.work.sum

# macOS
.DS_Store
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ gofumpt -w . # Format
- **Types are domain nouns**: `Finding`, `Report`, `Stats`, `Page`, `PageLink`, `Checker`, `RuleCheck`
- **Option functions use `With` prefix**: `WithChecks()`, `WithDepth()`, `WithConcurrency()`, `WithAllowPrivateIPs()`
- **Preset options are bare vars**: `Quick`, `Standard`, `Deep`, `SecurityOnly`, `CI` — exported `var Option` values
- **Severity is a type alias**: `type Severity = types.Severity` from `hawk/shared/types` — shared across hawk-eco
- **Severity is a type alias**: `type Severity = types.Severity` from `hawk-core-contracts/types` — shared across hawk-eco
- **Internal adapters use `Adapter` suffix**: `ruleCheckAdapter`, `customCheckAdapter` — bridge public to internal interfaces
- **Check names are lowercase strings**: `"security"`, `"links"`, `"forms"`, `"a11y"`, `"performance"` — used in `WithChecks()`
- **Error handling**: `Scan()` returns `(*Report, error)` — validation errors for empty URL, nil errors for success
Expand Down Expand Up @@ -94,7 +94,7 @@ gofumpt -w . # Format
| Scanner implementation | `scanner.go` (crawler orchestration, check execution) |
| Configuration & presets | `options.go` (`config` struct, `With*` functions, presets) |
| Config file loading | `config.go` (`.inspect.toml` parsing, `LoadConfig()`) |
| Severity type alias | `severity.go` (re-exports from `hawk/shared/types`) |
| Severity type alias | `severity.go` (re-exports from `hawk-core-contracts/types`) |
| SARIF output | `sarif.go` |
| CI output formatting | `ci_output.go` |
| Built-in checks | `checks/` directory |
Expand Down
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,12 @@ GOVULNCHECK := $(GOBIN_DIR)/govulncheck
# ---------------------------------------------------------------------------
# Phony declarations (alphabetical).
# ---------------------------------------------------------------------------
.PHONY: all bench build ci clean cover fmt help lint lint-fix \
.PHONY: all bench boundaries build ci clean cover fmt help lint lint-fix \
security test test-10x test-race tidy version vet

boundaries: ## Enforce support-repo import boundaries.
bash ./scripts/check-ecosystem-boundaries.sh

# ---------------------------------------------------------------------------
# Default target.
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -93,7 +96,7 @@ tidy: ## Tidy go.mod / go.sum.
# ---------------------------------------------------------------------------
# Composite gate used by CI and pre-push.
# ---------------------------------------------------------------------------
ci: tidy fmt vet lint test-race security ## Run everything CI runs.
ci: tidy fmt vet lint boundaries test-race security ## Run everything CI runs.
@echo "All CI checks passed."

# ---------------------------------------------------------------------------
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ handling, and SSRF protection), runs each check against the discovered pages,
and returns findings with severity levels. Results can be emitted as SARIF for
the GitHub Security tab.

## Ecosystem Boundaries

Inspect is a Hawk support engine. Keep the dependency edge one-way:

- use `hawk-core-contracts` for any cross-repo shared contracts
- do not import `hawk/internal/*`
- do not import removed legacy path `hawk/shared/types`; use `hawk-core-contracts/types`

## Quick Start

```go
Expand Down
53 changes: 53 additions & 0 deletions contracts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package inspect

import verifycontracts "github.com/GrayCodeAI/hawk-core-contracts/verify"

// ToContractFinding converts an inspect finding into the shared verification contract.
func ToContractFinding(f Finding) verifycontracts.Finding {
return verifycontracts.Finding{
Check: f.Check,
Severity: f.Severity,
URL: f.URL,
Element: f.Element,
Message: f.Message,
Fix: f.Fix,
Evidence: f.Evidence,
}
}

// ToContractFindings converts inspect findings into shared verification contracts.
func ToContractFindings(findings []Finding) []verifycontracts.Finding {
if len(findings) == 0 {
return nil
}
out := make([]verifycontracts.Finding, len(findings))
for i, f := range findings {
out[i] = ToContractFinding(f)
}
return out
}

func toContractStats(s Stats) verifycontracts.Stats {
return verifycontracts.Stats{
PagesScanned: s.PagesScanned,
FindingsTotal: s.FindingsTotal,
BySeverity: s.BySeverity,
ByCheck: s.ByCheck,
DurationPerCheck: s.DurationPerCheck,
}
}

// ToContractReport converts an inspect report into the shared verification contract.
func ToContractReport(r *Report) *verifycontracts.Report {
if r == nil {
return nil
}
return &verifycontracts.Report{
Target: r.Target,
Findings: ToContractFindings(r.Findings),
Stats: toContractStats(r.Stats),
CrawledURLs: r.CrawledURLs,
Duration: r.Duration,
FailOn: r.FailOn,
}
}
41 changes: 41 additions & 0 deletions contracts_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package inspect

import "testing"

func TestToContractReport(t *testing.T) {
t.Parallel()

report := &Report{
Target: "https://example.com",
CrawledURLs: 3,
Findings: []Finding{
{
Check: "security",
Severity: SeverityHigh,
URL: "https://example.com/login",
Message: "missing header",
},
},
Stats: Stats{
PagesScanned: 2,
FindingsTotal: 1,
BySeverity: map[Severity]int{SeverityHigh: 1},
ByCheck: map[string]int{"security": 1},
},
FailOn: SeverityMedium,
}

got := ToContractReport(report)
if got == nil {
t.Fatal("expected non-nil contract report")
}
if got.Target != report.Target {
t.Fatalf("Target = %q, want %q", got.Target, report.Target)
}
if got.Stats.PagesScanned != 2 {
t.Fatalf("PagesScanned = %d, want 2", got.Stats.PagesScanned)
}
if len(got.Findings) != 1 || got.Findings[0].URL != "https://example.com/login" {
t.Fatalf("unexpected findings conversion: %+v", got.Findings)
}
}
2 changes: 1 addition & 1 deletion docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ inspect/
├── options.go ⚙️ config, With* options, presets (Quick/Standard/Deep/…)
├── check.go 🛡️ Checker interface, RuleCheck, RegisterCheck/RegisterRule
├── config.go 📋 .inspect config loading
├── severity.go 🎚️ Severity (aliased from hawk/shared/types)
├── severity.go 🎚️ Severity (aliased from hawk-core-contracts/types)
├── sarif.go 📊 GenerateSARIF — SARIF 2.1.0 output
├── browser.go 🌐 BrowserEngine interface + page-data types (no rod import)
├── browser_fetcher.go 🔌 Adapts a BrowserEngine into the crawler's fetcher
Expand Down
2 changes: 1 addition & 1 deletion go.mod

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 0 additions & 10 deletions go.work

This file was deleted.

2 changes: 1 addition & 1 deletion internal/check/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ package check
import (
"context"

"github.com/GrayCodeAI/hawk/shared/types"
"github.com/GrayCodeAI/hawk-core-contracts/types"
"github.com/GrayCodeAI/inspect/internal/crawler"
)

Expand Down
2 changes: 1 addition & 1 deletion internal/report/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"strings"
"time"

"github.com/GrayCodeAI/hawk/shared/types"
"github.com/GrayCodeAI/hawk-core-contracts/types"
)

// Severity mirrors the public type.
Expand Down
15 changes: 15 additions & 0 deletions lefthook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,18 @@ commit-msg:
echo " full guide: https://www.conventionalcommits.org/"
exit 1
fi

strip-co-authored-by:
run: |
# Strip Co-authored-by: trailers that AI tools (Claude, Cursor, etc.) add.
# This enforces the rule that commits list only the human author.
sed '/^[Cc]o-[Aa]uthored-[Bb]y:/d' "{1}" > "{1}.tmp" && mv "{1}.tmp" "{1}"

# ---------------------------------------------------------------------------
# prepare-commit-msg — strip AI co-author trailers after tools inject them.
# ---------------------------------------------------------------------------
prepare-commit-msg:
commands:
strip-co-authored-by:
run: |
sed '/^[Cc]o-[Aa]uthored-[Bb]y:/d' "{1}" > "{1}.tmp" && mv "{1}.tmp" "{1}"
21 changes: 21 additions & 0 deletions scripts/check-ecosystem-boundaries.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env bash
set -euo pipefail

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT_DIR"

violations="$(
rg -n 'github\.com/GrayCodeAI/hawk/(internal/|shared/types)' \
--glob '*.go' \
. || true
)"

if [[ -n "${violations}" ]]; then
echo "forbidden Hawk imports found:"
echo "${violations}"
echo
echo "support repos must use hawk-core-contracts or local contracts, not hawk/internal or removed hawk/shared/types"
exit 1
fi

echo "ecosystem boundary guard passed"
2 changes: 1 addition & 1 deletion severity.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package inspect

import "github.com/GrayCodeAI/hawk/shared/types"
import "github.com/GrayCodeAI/hawk-core-contracts/types"

// Severity represents the impact level of a finding.
// Aliased from shared types for cross-module compatibility.
Expand Down
Loading