fix: reduce AS-006 false positives on non-execution tool names #205
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: ["main", "master", "dev"] | |
| pull_request: | |
| branches: ["main", "master", "dev"] | |
| # Cancel redundant runs on the same branch/PR | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| source: | |
| name: Prepare Source Tree | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Package source tree | |
| run: tar --exclude='.git' -czf /tmp/source-tree.tar.gz . | |
| - name: Upload source tree | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: source-tree | |
| path: /tmp/source-tree.tar.gz | |
| retention-days: 1 | |
| # ── 1. Test ──────────────────────────────────────────────────────────────── | |
| test: | |
| name: Test (Go ${{ matrix.go }}) | |
| runs-on: ubuntu-latest | |
| needs: [source] | |
| permissions: | |
| id-token: write | |
| contents: read | |
| strategy: | |
| matrix: | |
| go: ["1.26"] | |
| steps: | |
| - name: Download source tree | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: source-tree | |
| path: /tmp/source | |
| - name: Extract source tree | |
| run: tar -xzf /tmp/source/source-tree.tar.gz -C "$GITHUB_WORKSPACE" | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: ${{ matrix.go }} | |
| cache: true | |
| - name: Download modules | |
| run: go mod download | |
| - name: Verify modules | |
| run: go mod verify | |
| - name: Run all tests with race detector | |
| run: go test -race -count=1 -timeout=120s ./... | |
| - name: Run coverage (pkg/ + internal/ only) | |
| # cmd/ packages are integration wiring with no unit tests; excluding | |
| # them keeps the coverage metric representative of business logic. | |
| run: go test -race -count=1 -coverprofile=coverage.out ./pkg/... ./internal/... | |
| - name: Check test coverage threshold (≥60%) | |
| run: | | |
| COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | tr -d '%') | |
| echo "Total coverage: ${COVERAGE}%" | |
| if (( $(echo "$COVERAGE < 60" | bc -l) )); then | |
| echo "Coverage ${COVERAGE}% is below minimum threshold of 60%" | |
| exit 1 | |
| fi | |
| - name: Upload coverage to GitHub summary | |
| run: | | |
| go tool cover -func=coverage.out >> $GITHUB_STEP_SUMMARY | |
| - name: Upload coverage to Codecov | |
| if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository | |
| uses: codecov/codecov-action@v4 | |
| with: | |
| use_oidc: true | |
| files: coverage.out | |
| flags: unittests | |
| fail_ci_if_error: false # don't break CI if Codecov is unreachable | |
| - name: Skip Codecov on fork pull requests | |
| if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository | |
| run: echo "Skipping Codecov upload for fork PR because GitHub does not expose the OIDC token in this context." | |
| - name: Upload coverage artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-report | |
| path: coverage.out | |
| retention-days: 7 | |
| # ── 2. Lint ──────────────────────────────────────────────────────────────── | |
| lint: | |
| name: Lint | |
| runs-on: ubuntu-latest | |
| needs: [source] | |
| steps: | |
| - name: Download source tree | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: source-tree | |
| path: /tmp/source | |
| - name: Extract source tree | |
| run: tar -xzf /tmp/source/source-tree.tar.gz -C "$GITHUB_WORKSPACE" | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: "1.26" | |
| cache: true | |
| - name: Run golangci-lint | |
| uses: golangci/golangci-lint-action@v7 | |
| with: | |
| version: v2.10.1 | |
| args: --timeout=5m | |
| # ── 3. Build ─────────────────────────────────────────────────────────────── | |
| build: | |
| name: Build | |
| runs-on: ubuntu-latest | |
| needs: [source, test] | |
| steps: | |
| - name: Download source tree | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: source-tree | |
| path: /tmp/source | |
| - name: Extract source tree | |
| run: tar -xzf /tmp/source/source-tree.tar.gz -C "$GITHUB_WORKSPACE" | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: "1.26" | |
| cache: true | |
| - name: Build CLI (tooltrust-scanner) | |
| run: go build -v ./cmd/tooltrust-scanner/... | |
| - name: Build MCP Server | |
| run: go build -v ./cmd/tooltrust-mcp/... | |
| # ── 4. ToolTrust Scanner scans itself (self-scan) ──────────────────────── | |
| self-scan: | |
| name: ToolTrust Self-Scan | |
| runs-on: ubuntu-latest | |
| needs: [source, build] | |
| steps: | |
| - name: Download source tree | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: source-tree | |
| path: /tmp/source | |
| - name: Extract source tree | |
| run: tar -xzf /tmp/source/source-tree.tar.gz -C "$GITHUB_WORKSPACE" | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: "1.26" | |
| cache: true | |
| - name: Build tooltrust-scanner binary | |
| run: go build -o /tmp/tooltrust-scanner ./cmd/tooltrust-scanner/ | |
| - name: Run ToolTrust Scanner self-scan (testdata fixture) | |
| run: | | |
| /tmp/tooltrust-scanner scan \ | |
| --protocol mcp \ | |
| --input testdata/tools.json \ | |
| --output json --file /tmp/scan_report.json | |
| cat /tmp/scan_report.json | |
| - name: Validate --fail-on flag (must not BLOCK safe tools) | |
| run: | | |
| /tmp/tooltrust-scanner scan \ | |
| --protocol mcp \ | |
| --input testdata/tools.json \ | |
| --fail-on block || { | |
| echo "::error::ToolTrust Scanner self-scan found BLOCKED tool(s) in testdata/tools.json" | |
| exit 1 | |
| } | |
| - name: Upload scan report | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: tooltrust-scanner-scan-report | |
| path: /tmp/scan_report.json | |
| retention-days: 30 | |
| # ── 5. Verify install guide (go install + binary) ─────────────────────────── | |
| verify-install: | |
| name: Verify Install Guide | |
| runs-on: ubuntu-latest | |
| needs: [source] | |
| steps: | |
| - name: Download source tree | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: source-tree | |
| path: /tmp/source | |
| - name: Extract source tree | |
| run: tar -xzf /tmp/source/source-tree.tar.gz -C "$GITHUB_WORKSPACE" | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: "1.26" | |
| cache: true | |
| - name: Verify go install (README primary method) | |
| run: | | |
| # Use @main: v0.1.2 lacks cmd/tooltrust-scanner; main has correct structure | |
| go install github.com/AgentSafe-AI/tooltrust-scanner/cmd/tooltrust-scanner@main | |
| BIN="$(go env GOPATH)/bin/tooltrust-scanner" | |
| $BIN version | |
| $BIN scan --protocol mcp --input testdata/tools.json --output text | |
| echo "✓ go install works" | |
| - name: Verify pre-built binary download (requires v0.1.3+) | |
| continue-on-error: true | |
| run: | | |
| OS=linux | |
| ARCH=amd64 | |
| URL="https://github.com/AgentSafe-AI/tooltrust-scanner/releases/latest/download/tooltrust-scanner_${OS}_${ARCH}" | |
| if curl -sfSL -o /tmp/tooltrust-scanner_bin "$URL"; then | |
| chmod +x /tmp/tooltrust-scanner_bin | |
| /tmp/tooltrust-scanner_bin version | |
| /tmp/tooltrust-scanner_bin scan --protocol mcp --input testdata/tools.json --output text | |
| echo "✓ pre-built binary works" | |
| else | |
| echo "::notice::Pre-built binary not found (expected until v0.1.3 release)" | |
| fi | |
| # ── 6. Verify Homebrew install (macOS) ────────────────────────────────────── | |
| verify-install-homebrew: | |
| name: Verify Install (Homebrew) | |
| runs-on: macos-latest | |
| needs: [source] | |
| steps: | |
| - name: Download source tree | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: source-tree | |
| path: /tmp/source | |
| - name: Extract source tree | |
| run: tar -xzf /tmp/source/source-tree.tar.gz -C "$GITHUB_WORKSPACE" | |
| - name: Install via Homebrew Formula | |
| run: | | |
| # Homebrew rejects direct URL install; create a local tap and install from it | |
| brew tap-new --no-git AgentSafe-AI/tooltrust-scanner | |
| TAP_DIR="$(brew --prefix)/Library/Taps/agentsafe-ai/homebrew-tooltrust-scanner" | |
| mkdir -p "$TAP_DIR/Formula" | |
| cp "$GITHUB_WORKSPACE/Formula/tooltrust-scanner.rb" "$TAP_DIR/Formula/" | |
| # Get version from formula | |
| VERSION=$(awk '/version "/ {print $2}' "$TAP_DIR/Formula/tooltrust-scanner.rb" | tr -d '"') | |
| # Homebrew expects the unpacked folder to be named <formula>-<version> | |
| TEST_DIR="/tmp/brew-test/tooltrust-scanner-${VERSION}" | |
| mkdir -p "$TEST_DIR" | |
| rsync -a "$GITHUB_WORKSPACE/" "$TEST_DIR/" --exclude ".git" | |
| tar -czf /tmp/ci_source.tar.gz -C /tmp/brew-test "tooltrust-scanner-${VERSION}" | |
| URL="file:///tmp/ci_source.tar.gz" | |
| SHA256=$(shasum -a 256 /tmp/ci_source.tar.gz | awk '{print $1}') | |
| sed -i '' "s|url \".*\"|url \"$URL\"|" "$TAP_DIR/Formula/tooltrust-scanner.rb" | |
| sed -i '' "s|sha256 \".*\"|sha256 \"$SHA256\"|" "$TAP_DIR/Formula/tooltrust-scanner.rb" | |
| brew install AgentSafe-AI/tooltrust-scanner/tooltrust-scanner | |
| tooltrust-scanner version | |
| tooltrust-scanner scan --protocol mcp --input testdata/tools.json --output text | |
| echo "✓ Homebrew install works" | |
| - name: Uninstall | |
| if: always() | |
| run: brew uninstall tooltrust-scanner 2>/dev/null || true |