Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
ca4914c
fix(session): harden runtime control paths
aksOps Jul 12, 2026
f9baa7f
fix: harden terminal display boundaries
aksOps Jul 12, 2026
4c1ecef
fix(lifecycle): close persistence races
aksOps Jul 12, 2026
eec7df9
perf(discovery): decouple PR enrichment
aksOps Jul 12, 2026
995ccee
test(discovery): characterize PR refresh paths
aksOps Jul 12, 2026
1beb570
fix: harden CLI startup and logging
aksOps Jul 12, 2026
83c9a31
fix(session): verify portable process identity
aksOps Jul 12, 2026
8650e16
test(cli): create owner-only runtime fixtures
aksOps Jul 12, 2026
0f62d90
test: bound in-process host readiness
aksOps Jul 12, 2026
a41c528
test: use short Darwin session paths
aksOps Jul 12, 2026
c352dfe
build: use Go 1.25.12 toolchain
aksOps Jul 12, 2026
8c98d10
chore(deps): upgrade x/term to 0.2.2
aksOps Jul 12, 2026
e3f2aaa
chore(deps): upgrade go-runewidth to 0.0.24
aksOps Jul 12, 2026
d38383f
test: add fuzz and release smoke coverage
aksOps Jul 12, 2026
5b938d1
ci: bound Darwin lifecycle smoke tests
aksOps Jul 12, 2026
a0187b3
ci: enforce least-privilege release gates
aksOps Jul 12, 2026
3f2f08d
test: restore coverage and remove duplicate routing
aksOps Jul 12, 2026
071050e
fix(pr): enforce refresh pass deadlines
aksOps Jul 12, 2026
ae1f883
refactor: simplify hardened control paths
aksOps Jul 12, 2026
5b94e78
chore(security): document validated filesystem boundaries
aksOps Jul 12, 2026
5810dea
docs: define Windows support via WSL2
aksOps Jul 12, 2026
35af55f
chore: ignore graphify output artifacts
aksOps Jul 12, 2026
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
1 change: 0 additions & 1 deletion .claude/worktrees/plan-review-edits
Submodule plan-review-edits deleted from 98a386
69 changes: 54 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,83 @@ name: CI
on:
push:
pull_request:
workflow_call:
workflow_dispatch:

permissions:
contents: read

jobs:
build-test-lint:
name: Build, test, and lint
build:
name: build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version-file: go.mod
cache: true

- name: Verify modules
run: go mod verify

- name: Build
run: go build ./...

- name: Vet
run: go vet ./...
test-race:
name: test-race
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version-file: go.mod
cache: true

- name: Test with race detector and coverage
run: go test -race -count=1 -covermode=atomic -coverpkg=./... -coverprofile=coverage.out ./...

- name: Enforce coverage floor
shell: bash
run: |
coverage="$(go tool cover -func=coverage.out | awk '$1 == "total:" {gsub("%", "", $3); print $3}')"
awk -v coverage="${coverage}" 'BEGIN { if (coverage + 0 < 88.1) { printf "coverage %.1f%% is below 88.1%%\n", coverage; exit 1 } }'

lint:
name: lint
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version-file: go.mod
cache: true

- name: Check gofmt
shell: bash
run: |
unformatted="$(gofmt -l . | grep -v '^vendor/' || true)"
if [ -n "$unformatted" ]; then
echo "The following files are not gofmt-clean:"
echo "$unformatted"
exit 1
fi
test -z "${unformatted}" || { printf 'The following files are not gofmt-clean:\n%s\n' "${unformatted}"; exit 1; }

- name: Vet
run: go vet ./...

- name: Test
run: go test -race -cover ./...
- name: Staticcheck
run: |
go install honnef.co/go/tools/cmd/staticcheck@2025.1.1
staticcheck ./...

- name: Lint
uses: golangci/golangci-lint-action@9fae48acfc02a90574d7c304a1758ef9895495fa # v7
- name: GolangCI-Lint
uses: golangci/golangci-lint-action@9fae48acfc02a90574d7c304a1758ef9895495fa # v7.0.1
with:
version: v2.5.0
install-mode: goinstall
Expand Down
40 changes: 40 additions & 0 deletions .github/workflows/fuzz.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Scheduled fuzzing

on:
schedule:
- cron: "41 4 * * 2"
workflow_dispatch:

permissions:
contents: read

jobs:
fuzz:
name: fuzz-${{ matrix.target }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- package: ./internal/session
target: FuzzFrameDecoding
- package: ./internal/vterm
target: FuzzTerminalInput
- package: ./internal/displaytext
target: FuzzSanitize
- package: ./internal/session
target: FuzzAttachFiltering
- package: ./internal/session
target: FuzzStateDecoding
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0

- name: Set up Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: go.mod
cache: true

- name: Fuzz for 30 seconds
run: go test "${{ matrix.package }}" -run=^$ -fuzz="^${{ matrix.target }}$" -fuzztime=30s
86 changes: 86 additions & 0 deletions .github/workflows/release-smoke.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: Release smoke

on:
push:
branches: [main]
pull_request:
workflow_dispatch:

permissions:
contents: read

concurrency:
group: release-smoke-${{ github.event.pull_request.head.ref || github.ref_name }}
cancel-in-progress: true

jobs:
snapshot:
name: GoReleaser snapshot
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0

- name: Set up Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: go.mod
cache: true

- name: Validate GoReleaser configuration
uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7.2.3
with:
distribution: goreleaser
version: v2.17.0
args: check

- name: Build snapshot archives
uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7.2.3
with:
distribution: goreleaser
version: v2.17.0
args: release --snapshot --clean --skip=sign,sbom

- name: Verify archive names and contents
shell: bash
run: |
mapfile -t archives < <(find dist -maxdepth 1 -type f -name 'uam_*.tar.gz' -print | sort)
test "${#archives[@]}" -eq 4
for archive in "${archives[@]}"; do
basename "${archive}" | grep -Eq '^uam_.+_(linux|darwin)_(amd64|arm64)\.tar\.gz$'
tar -tzf "${archive}" | grep -Eq '(^|/)uam$'
done
linux_archive="$(find dist -maxdepth 1 -type f -name 'uam_*_linux_amd64.tar.gz' -print -quit)"
test -n "${linux_archive}"
mkdir -p /tmp/uam-release-smoke
tar -xzf "${linux_archive}" -C /tmp/uam-release-smoke
binary="$(find /tmp/uam-release-smoke -type f -name uam -print -quit)"
test -n "${binary}"
"${binary}" version | grep -E '.+'

darwin-native:
name: Darwin-native lifecycle and version smoke
runs-on: macos-14
timeout-minutes: 8
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0

- name: Set up Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: go.mod
cache: true

- name: Run native session lifecycle tests
run: go test -race -count=1 -timeout=4m ./internal/session

- name: Run stop, restart, and resume tests
run: go test -race -count=1 -timeout=2m ./internal/app

- name: Build and run version command
run: |
go build -o "${RUNNER_TEMP}/uam" ./cmd/uam
"${RUNNER_TEMP}/uam" version | grep -E '.+'
57 changes: 49 additions & 8 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,63 @@ on:
- "v*"

permissions:
contents: write
id-token: write
packages: read
contents: read

jobs:
goreleaser:
name: GoReleaser
quality:
name: Quality verification
uses: ./.github/workflows/ci.yml

security:
name: Security verification
uses: ./.github/workflows/security.yml

ancestry:
name: Verify tag is on main
runs-on: ubuntu-latest
steps:
- name: Checkout tagged commit
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0

- name: Verify tagged commit is an ancestor of main
run: |
git fetch --no-tags origin main
git merge-base --is-ancestor "${GITHUB_SHA}" origin/main

release-config:
name: Validate release configuration
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0

- name: Validate GoReleaser configuration
uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0
with:
version: "~> v2"
args: check

publish:
name: Publish release
needs: [quality, security, ancestry, release-config]
runs-on: ubuntu-latest
environment: release
permissions:
contents: write
id-token: write
packages: read
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0

- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version-file: go.mod
cache: true
Expand All @@ -33,7 +74,7 @@ jobs:
uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3.7.0

- name: Run GoReleaser
uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6
uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0
with:
version: "~> v2"
args: release --clean
Expand Down
46 changes: 16 additions & 30 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,72 +4,58 @@ on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: "23 3 * * 1"
workflow_call:
workflow_dispatch:

permissions:
contents: read
actions: read
security-events: write
pull-requests: read

jobs:
govulncheck:
name: Go vulnerability check
name: govulncheck
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version-file: go.mod
cache: true

- name: Install govulncheck
run: go install golang.org/x/vuln/cmd/govulncheck@v1.3.0

- name: Run govulncheck
run: govulncheck ./...
run: |
go install golang.org/x/vuln/cmd/govulncheck@v1.3.0
govulncheck ./...

gosec:
name: Gosec static analysis
name: gosec
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version-file: go.mod
cache: true

- name: Install gosec
run: go install github.com/securego/gosec/v2/cmd/gosec@v2.26.1

- name: Run gosec
run: gosec -exclude-dir=.claude -exclude-dir=vendor -fmt=sarif -out=gosec.sarif ./...

- name: Upload gosec SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: gosec.sarif
run: |
go install github.com/securego/gosec/v2/cmd/gosec@v2.26.1
gosec -exclude-dir=.claude -exclude-dir=vendor ./...

dependency-review:
name: Dependency review
name: dependency-review
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Review dependency changes
uses: actions/dependency-review-action@v4
uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 # v4.8.2
Loading
Loading