Skip to content
Merged
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
61 changes: 15 additions & 46 deletions .github/actions/checkout-eyrie/action.yml
Original file line number Diff line number Diff line change
@@ -1,68 +1,37 @@
name: Checkout ecosystem
description: Clone graycode-eco ecosystem repos into hawk/external for hawk go.work
description: Clone graycode-eco sibling repos into the workspace parent for hawk's go.work

inputs:
ref:
description: Git ref to checkout only when allow_branch_fallback is true
description: Git ref to checkout (falls back to main)
required: false
default: main
allow_branch_fallback:
description: >
When true, clone a branch head if the Gitlink is missing (dev-only escape hatch).
Default false — missing or unreachable pins fail the job so releases never
silently track main.
required: false
default: "false"

runs:
using: composite
steps:
- name: Clone ecosystem repos
- name: Clone sibling repos
shell: bash
env:
# Passed via env (not ${{ }} interpolation into the script) so an
# attacker-controlled ref (e.g. a fork branch name) cannot inject shell.
# Passed via env (not ${{ }} interpolation) so an attacker-controlled
# ref (e.g. a fork branch name) cannot inject shell.
INPUT_REF: ${{ inputs.ref }}
ALLOW_BRANCH_FALLBACK: ${{ inputs.allow_branch_fallback }}
run: |
set -euo pipefail
mkdir -p "${GITHUB_WORKSPACE}/external"
for repo in hawk-core-contracts eyrie inspect sight tok trace yaad; do
dest="${GITHUB_WORKSPACE}/external/${repo}"
# hawk's committed go.work references ../<repo>, so the siblings must
# be cloned into the parent of the checked-out workspace.
ws_parent="$(cd "${GITHUB_WORKSPACE}/.." && pwd)"
for repo in hawk-core-contracts eyrie inspect sight tok trace yaad hawk-mcpkit; do
dest="${ws_parent}/${repo}"
if [ -d "$dest/.git" ]; then
echo "$repo already present at $dest"
continue
fi
commit=$(git ls-tree HEAD "external/${repo}" | awk '{print $3}' || true)
if [ -n "$commit" ]; then
echo "Cloning $repo at submodule commit $commit"
# Full clone so the pinned commit is reachable even after
# the dependency repo's main has been rewritten past it
# (e.g. by a squash-merge). A depth-1 clone can't check
# out older commits and fails with "unable to read tree".
git clone "https://github.com/GrayCodeAI/${repo}.git" "$dest"
if ! (cd "$dest" && git checkout --quiet "$commit"); then
echo "::error::Pinned submodule commit $commit is not reachable in $repo"
echo "Refusing to test an unpinned branch head for a pinned Hawk commit."
exit 1
fi
if git ls-remote --heads "https://github.com/GrayCodeAI/${repo}.git" "$INPUT_REF" | grep -q .; then
echo "Cloning $repo at branch $INPUT_REF"
git clone --depth=1 --branch "$INPUT_REF" "https://github.com/GrayCodeAI/${repo}.git" "$dest"
else
if [ "${ALLOW_BRANCH_FALLBACK}" != "true" ]; then
echo "::error::Missing Gitlink for external/${repo} at HEAD"
echo "Hawk requires a pinned submodule commit for every engine."
echo "Record the pin with: git submodule update --init external/${repo}"
echo "and commit the Gitlink. Branch-head fallback is disabled by default"
echo "(set allow_branch_fallback=true only for local experiments)."
exit 1
fi
ref="$INPUT_REF"
# Optional escape hatch: fall back to main if the branch doesn't exist.
if ! git ls-remote --heads "https://github.com/GrayCodeAI/${repo}.git" "$ref" | grep -q .; then
echo "Branch '$ref' not found on $repo, falling back to main"
ref="main"
fi
echo "::warning::Cloning $repo at branch head '$ref' (no Gitlink; allow_branch_fallback=true)"
git clone --depth=1 --branch "$ref" \
"https://github.com/GrayCodeAI/${repo}.git" "$dest"
echo "Branch '$INPUT_REF' not found on $repo, falling back to main"
git clone --depth=1 --branch main "https://github.com/GrayCodeAI/${repo}.git" "$dest"
fi
done
28 changes: 16 additions & 12 deletions .github/actions/setup-deps/action.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: Setup Dependencies
description: Clone ecosystem deps with retry, setup Go, create workspace
description: Clone ecosystem sibling repos with retry, setup Go, sync workspace

inputs:
go-version:
Expand All @@ -12,7 +12,7 @@ inputs:
runs:
using: composite
steps:
- name: Checkout dependencies
- name: Checkout sibling dependencies
shell: bash
env:
GH_TOKEN: ${{ inputs.token }}
Expand All @@ -25,21 +25,25 @@ runs:
done
echo "Failed to clone $repo after 3 attempts" && return 1
}
mkdir -p external
clone_with_retry hawk-core-contracts external/hawk-core-contracts main
clone_with_retry eyrie external/eyrie main
clone_with_retry tok external/tok main
clone_with_retry yaad external/yaad main
clone_with_retry inspect external/inspect main
clone_with_retry sight external/sight main
clone_with_retry trace external/trace main
ws_parent="$(cd "${GITHUB_WORKSPACE}/.." && pwd)"
mkdir -p "$ws_parent"
clone_with_retry hawk-core-contracts "$ws_parent/hawk-core-contracts" main
clone_with_retry eyrie "$ws_parent/eyrie" main
clone_with_retry tok "$ws_parent/tok" main
clone_with_retry yaad "$ws_parent/yaad" main
clone_with_retry inspect "$ws_parent/inspect" main
clone_with_retry sight "$ws_parent/sight" main
clone_with_retry trace "$ws_parent/trace" main
clone_with_retry hawk-mcpkit "$ws_parent/hawk-mcpkit" main

- name: Set up Go
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: ${{ inputs.go-version }}

- name: Create workspace
- name: Sync workspace
shell: bash
run: |
printf 'go 1.26.6\n\nuse .\n\nreplace (\n\tgithub.com/GrayCodeAI/hawk-core-contracts => ./external/hawk-core-contracts\n\tgithub.com/GrayCodeAI/eyrie => ./external/eyrie\n\tgithub.com/GrayCodeAI/inspect => ./external/inspect\n\tgithub.com/GrayCodeAI/sight => ./external/sight\n\tgithub.com/GrayCodeAI/tok => ./external/tok\n\tgithub.com/GrayCodeAI/trace => ./external/trace\n\tgithub.com/GrayCodeAI/yaad => ./external/yaad\n\tgithub.com/GrayCodeAI/hawk-mcpkit => ./external/hawk-mcpkit\n)\n' > go.work
# hawk's committed go.work references the sibling repos; ensure it is
# consistent with the cloned siblings.
go work sync
41 changes: 10 additions & 31 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ concurrency:

env:
GO_VERSION: "1.26.6"
# GrayCodeAI sibling modules are resolved from the local external/ submodules via
# go.work; their go.mod require versions (v0.1.0) intentionally do not match the
# GrayCodeAI sibling modules are resolved from the workspace ../<repo> checkouts via
# go.work; their go.mod require versions intentionally do not match the
# frozen public proxy/sumdb snapshot, so bypass the proxy + checksum DB for them.
GOPRIVATE: "github.com/GrayCodeAI/*"
GONOSUMDB: "github.com/GrayCodeAI/*"
Expand Down Expand Up @@ -84,9 +84,6 @@ jobs:
- uses: ./.github/actions/checkout-eyrie
with:
ref: ${{ github.head_ref || github.ref_name }}
- name: Init hawk-mcpkit submodule
run: |
git submodule update --init external/hawk-mcpkit
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
Expand All @@ -104,11 +101,11 @@ jobs:
fi
- name: go mod verify
run: go mod verify
- name: workspace points at external checkouts
- name: workspace references sibling checkouts
run: |
for module in hawk-core-contracts eyrie inspect sight tok trace yaad hawk-mcpkit; do
if ! grep -q "./external/${module}" go.work; then
echo "::error::go.work must include ./external/${module}."
if ! grep -q "../${module}" go.work; then
echo "::error::go.work must include ../${module}."
cat go.work
exit 1
fi
Expand All @@ -133,9 +130,6 @@ jobs:
- uses: ./.github/actions/checkout-eyrie
with:
ref: ${{ github.head_ref || github.ref_name }}
- name: Init hawk-mcpkit submodule
run: |
git submodule update --init external/hawk-mcpkit
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
Expand All @@ -149,13 +143,16 @@ jobs:
go build -mod=readonly ./cmd/hawk
go test ./... -count=1 -timeout=300s -skip='TestDefaultSkillDirsCrossAgent|TestCopySelectionE2E'

submodule-release-parity:
name: submodule and module parity
release-parity:
name: workspace and module parity
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- uses: ./.github/actions/checkout-eyrie
with:
ref: ${{ github.head_ref || github.ref_name }}
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
Expand All @@ -175,9 +172,6 @@ jobs:
- uses: ./.github/actions/checkout-eyrie
with:
ref: ${{ github.head_ref || github.ref_name }}
- name: Init hawk-mcpkit submodule
run: |
git submodule update --init external/hawk-mcpkit
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
Expand All @@ -203,8 +197,6 @@ jobs:
- uses: ./.github/actions/checkout-eyrie
with:
ref: ${{ github.head_ref || github.ref_name }}
- name: Init hawk-mcpkit submodule
run: git submodule update --init external/hawk-mcpkit
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
Expand Down Expand Up @@ -234,8 +226,6 @@ jobs:
- uses: ./.github/actions/checkout-eyrie
with:
ref: ${{ github.head_ref || github.ref_name }}
- name: Init hawk-mcpkit submodule
run: git submodule update --init external/hawk-mcpkit
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
Expand Down Expand Up @@ -306,8 +296,6 @@ jobs:
- uses: ./.github/actions/checkout-eyrie
with:
ref: ${{ github.head_ref || github.ref_name }}
- name: Init hawk-mcpkit submodule
run: git submodule update --init external/hawk-mcpkit
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
Expand Down Expand Up @@ -416,9 +404,6 @@ jobs:
- uses: ./.github/actions/checkout-eyrie
with:
ref: ${{ github.head_ref || github.ref_name }}
- name: Init hawk-mcpkit submodule
run: |
git submodule update --init external/hawk-mcpkit
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c
with:
go-version: "${{ env.GO_VERSION }}"
Expand Down Expand Up @@ -477,8 +462,6 @@ jobs:
- uses: ./.github/actions/checkout-eyrie
with:
ref: ${{ github.head_ref || github.ref_name }}
- name: Init hawk-mcpkit submodule
run: git submodule update --init external/hawk-mcpkit
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
Expand Down Expand Up @@ -524,8 +507,6 @@ jobs:
- uses: ./.github/actions/checkout-eyrie
with:
ref: ${{ github.head_ref || github.ref_name }}
- name: Init hawk-mcpkit submodule
run: git submodule update --init external/hawk-mcpkit
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
Expand Down Expand Up @@ -553,8 +534,6 @@ jobs:
- uses: ./.github/actions/checkout-eyrie
with:
ref: ${{ github.head_ref || github.ref_name }}
- name: Init hawk-mcpkit submodule
run: git submodule update --init external/hawk-mcpkit
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
Expand Down
6 changes: 1 addition & 5 deletions .github/workflows/compatibility-matrix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ jobs:
- uses: ./.github/actions/checkout-eyrie
with:
ref: ${{ github.head_ref || github.ref_name }}
allow_branch_fallback: "true"
- name: Init hawk-mcpkit submodule
run: |
git submodule update --init external/hawk-mcpkit
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: "1.26.6"
Expand All @@ -38,6 +34,6 @@ jobs:
run: make compat-check
- name: Report 'next' matrix
run: make compat-test
- name: Pin freshness vs external/ (advisory)
- name: Pin freshness vs sibling repos (advisory)
run: make compat-drift
continue-on-error: true
28 changes: 17 additions & 11 deletions .github/workflows/daemon-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ on:
- "packaging/systemd/hawk-daemon.service"
- "internal/**"
- "cmd/**"
- "external/**"
- "go.mod"
- "go.sum"

Expand All @@ -31,8 +30,6 @@ jobs:
steps:
- name: Check out source
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
submodules: recursive

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
Expand Down Expand Up @@ -62,18 +59,27 @@ jobs:
BUILD_DATE=${{ github.event.head_commit.timestamp }}

- name: Scan daemon image with Trivy
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
uses: aquasecurity/setup-trivy@3fb12ec12f41e471780db15c232d5dd185dcb514
with:
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:scan
format: sarif
output: trivy-daemon-image.sarif
severity: CRITICAL,HIGH
version: v0.70.0
cache: true
- name: Run Trivy daemon scan (sarif)
shell: bash
run: |
# Go reachability is enforced separately by govulncheck in CI. The
# binary also carries the full workspace module graph, including
# non-reachable packages that Trivy reports as binary findings.
vuln-type: os
ignore-unfixed: true
exit-code: '1'
# CVE-2026-14456 (OpenSSL) is ignored via .trivyignore — the fixed
# libcrypto 3.5.8-r0 is not yet published in Alpine 3.23.
trivy image \
--severity CRITICAL,HIGH \
--ignore-unfixed \
--ignorefile "${GITHUB_WORKSPACE}/.trivyignore" \
--vuln-type os \
--format sarif \
--output trivy-daemon-image.sarif \
--exit-code 1 \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:scan

- name: Generate image metadata
id: meta
Expand Down
Loading
Loading