Skip to content

Commit 3b5ea80

Browse files
committed
feat: initial release of qctx 0.1.0
Quality context for AI agents. Single static Go binary that gathers SonarQube + Nexus IQ + GitLab MR/pipeline state into one normalized JSON (live) or JSONL artifact (pipeline snapshot) for AI-driven fix workflows. Highlights - Two modes: 'qctx fetch' (live JSON to stdout) and 'qctx snapshot --out report.jsonl' (pipeline artifact) - Enterprise-first: no public-cloud defaults, custom CA, proxy, SSO header injection, '--insecure' opt-out with stderr warning - Auto-discovers Sonar project key from GitLab pipeline job traces - Type-discriminated JSONL schema (meta / sonar.* / nexus.* / gitlab.* / error) - Filtering: --severity, --type, --branch, --all, --include-resolved, --no-sonar / --no-gitlab / --no-nexus, --strict - 93 tests, race-checked; per-package coverage gate (>= 80%) in CI - GoReleaser multi-platform binaries + distroless Docker image - GitHub Actions: CI, security (gosec, govulncheck, Trivy, CodeQL), Sonar - 7 ADRs (JSONL schema, enterprise networking, partial-success, Secret type, cobra, byte-stitching, retryablehttp) - Full design spec, 36-task implementation plan, enterprise & example docs
0 parents  commit 3b5ea80

98 files changed

Lines changed: 12527 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.dockerignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.git
2+
.gitlab-ci.yml
3+
bin/
4+
dist/
5+
coverage.out
6+
docs/
7+
test/
8+
*.md

.editorconfig

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
end_of_line = lf
6+
insert_final_newline = true
7+
trim_trailing_whitespace = true
8+
9+
[*.go]
10+
indent_style = tab
11+
indent_size = 4
12+
13+
[Makefile]
14+
indent_style = tab
15+
16+
[*.{md,yaml,yml,json}]
17+
indent_style = space
18+
indent_size = 2
19+
20+
[*.sh]
21+
indent_style = space
22+
indent_size = 2

.github/workflows/ci.yml

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
lint:
14+
name: Lint
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@v4
18+
- uses: actions/setup-go@v5
19+
with:
20+
go-version: '1.23'
21+
cache: true
22+
- name: golangci-lint
23+
uses: golangci/golangci-lint-action@v6
24+
with:
25+
version: v2.1.0
26+
27+
test:
28+
name: Test + coverage gate
29+
runs-on: ubuntu-latest
30+
steps:
31+
- uses: actions/checkout@v4
32+
- uses: actions/setup-go@v5
33+
with:
34+
go-version: '1.23'
35+
cache: true
36+
- name: Install goimports
37+
run: go install golang.org/x/tools/cmd/goimports@latest
38+
- name: Install golangci-lint (for lint inside make targets)
39+
run: go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.1.0
40+
- name: Tests with coverage
41+
run: make cover
42+
- name: Per-package coverage gate
43+
run: make cover-check
44+
- name: Upload coverage to Codecov
45+
uses: codecov/codecov-action@v4
46+
with:
47+
files: ./coverage.out
48+
fail_ci_if_error: false
49+
50+
build:
51+
name: Build
52+
runs-on: ubuntu-latest
53+
needs: [lint, test]
54+
steps:
55+
- uses: actions/checkout@v4
56+
- uses: actions/setup-go@v5
57+
with:
58+
go-version: '1.23'
59+
cache: true
60+
- name: Build
61+
run: make build
62+
- name: Smoke
63+
run: ./bin/qctx version
64+
65+
e2e:
66+
name: E2E
67+
runs-on: ubuntu-latest
68+
needs: [build]
69+
steps:
70+
- uses: actions/checkout@v4
71+
- uses: actions/setup-go@v5
72+
with:
73+
go-version: '1.23'
74+
cache: true
75+
- name: E2E
76+
run: make e2e
77+
78+
release:
79+
name: Release
80+
runs-on: ubuntu-latest
81+
needs: [lint, test, build, e2e]
82+
if: startsWith(github.ref, 'refs/tags/v')
83+
permissions:
84+
contents: write
85+
steps:
86+
- uses: actions/checkout@v4
87+
with:
88+
fetch-depth: 0
89+
- uses: actions/setup-go@v5
90+
with:
91+
go-version: '1.23'
92+
cache: true
93+
- name: GoReleaser
94+
uses: goreleaser/goreleaser-action@v6
95+
with:
96+
version: latest
97+
args: release --clean
98+
env:
99+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/security.yml

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
name: Security
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
schedule:
9+
- cron: '0 7 * * 1' # Mondays 07:00 UTC
10+
11+
permissions:
12+
contents: read
13+
security-events: write
14+
15+
jobs:
16+
gosec:
17+
name: gosec
18+
runs-on: ubuntu-latest
19+
steps:
20+
- uses: actions/checkout@v4
21+
- uses: actions/setup-go@v5
22+
with: { go-version: '1.23', cache: true }
23+
- name: Run gosec
24+
uses: securego/gosec@master
25+
with:
26+
args: '-no-fail -fmt sarif -out gosec.sarif ./...'
27+
- name: Upload SARIF
28+
uses: github/codeql-action/upload-sarif@v3
29+
if: always()
30+
with:
31+
sarif_file: gosec.sarif
32+
category: gosec
33+
34+
govulncheck:
35+
name: govulncheck
36+
runs-on: ubuntu-latest
37+
steps:
38+
- uses: actions/checkout@v4
39+
- uses: actions/setup-go@v5
40+
with: { go-version: '1.23', cache: true }
41+
- name: Install govulncheck
42+
run: go install golang.org/x/vuln/cmd/govulncheck@latest
43+
- name: Run govulncheck
44+
run: govulncheck ./...
45+
46+
trivy:
47+
name: Trivy filesystem scan
48+
runs-on: ubuntu-latest
49+
steps:
50+
- uses: actions/checkout@v4
51+
- name: Trivy scan
52+
uses: aquasecurity/trivy-action@0.24.0
53+
with:
54+
scan-type: fs
55+
scan-ref: .
56+
format: sarif
57+
output: trivy.sarif
58+
severity: CRITICAL,HIGH,MEDIUM
59+
ignore-unfixed: true
60+
- name: Upload SARIF
61+
uses: github/codeql-action/upload-sarif@v3
62+
if: always()
63+
with:
64+
sarif_file: trivy.sarif
65+
category: trivy
66+
67+
codeql:
68+
name: CodeQL
69+
runs-on: ubuntu-latest
70+
permissions:
71+
security-events: write
72+
actions: read
73+
contents: read
74+
steps:
75+
- uses: actions/checkout@v4
76+
- uses: actions/setup-go@v5
77+
with: { go-version: '1.23', cache: true }
78+
- name: Initialize CodeQL
79+
uses: github/codeql-action/init@v3
80+
with:
81+
languages: go
82+
- name: Build
83+
run: go build ./...
84+
- name: Analyze
85+
uses: github/codeql-action/analyze@v3
86+
with:
87+
category: "/language:go"

.github/workflows/sonar.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
name: Sonar
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
permissions:
10+
contents: read
11+
pull-requests: read
12+
13+
jobs:
14+
sonarcloud:
15+
name: SonarCloud
16+
runs-on: ubuntu-latest
17+
steps:
18+
- uses: actions/checkout@v4
19+
with:
20+
fetch-depth: 0 # Sonar wants full git history for blame
21+
- uses: actions/setup-go@v5
22+
with:
23+
go-version: '1.23'
24+
cache: true
25+
- name: Tests with coverage
26+
run: go test -race -coverprofile=coverage.out -covermode=atomic ./...
27+
- name: SonarCloud scan
28+
uses: SonarSource/sonarqube-scan-action@v4
29+
env:
30+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
31+
with:
32+
args: >
33+
-Dsonar.projectKey=RandomCodeSpace_qctx
34+
-Dsonar.organization=randomcodespace
35+
-Dsonar.go.coverage.reportPaths=coverage.out
36+
-Dsonar.sources=.
37+
-Dsonar.exclusions=**/*_test.go,**/test/**,**/vendor/**,**/docs/**
38+
-Dsonar.tests=.
39+
-Dsonar.test.inclusions=**/*_test.go

.gitignore

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Build output
2+
/bin/
3+
/dist/
4+
/qctx
5+
/qctx.exe
6+
7+
# Test output
8+
*.test
9+
*.out
10+
coverage.out
11+
coverage.html
12+
13+
# Editor
14+
.idea/
15+
.vscode/
16+
*.swp
17+
18+
# OS
19+
.DS_Store
20+
21+
# Secrets and runtime files
22+
.env
23+
.env.local
24+
*.token
25+
~/.qctx.yaml
26+
.qctx.yaml
27+
28+
# GoReleaser
29+
dist/
30+
31+
# Ralph Loop state
32+
.claude/

.gitlab-ci.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
stages: [lint, test, build, release]
2+
3+
default:
4+
image: golang:1.23-alpine
5+
before_script:
6+
- apk add --no-cache git make bash curl
7+
- go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.1.0
8+
- export PATH="$PATH:$(go env GOPATH)/bin"
9+
10+
lint:
11+
stage: lint
12+
script: [make lint]
13+
14+
test:
15+
stage: test
16+
script: [make cover]
17+
coverage: '/total:\s+\(statements\)\s+(\d+\.\d+)%/'
18+
artifacts:
19+
paths: [coverage.out]
20+
expire_in: 1 week
21+
22+
build:
23+
stage: build
24+
script: [make build]
25+
artifacts:
26+
paths: [bin/qctx]
27+
expire_in: 1 week
28+
29+
e2e:
30+
stage: build
31+
needs: [build]
32+
script: [make e2e]
33+
34+
release:
35+
stage: release
36+
rules:
37+
- if: $CI_COMMIT_TAG
38+
image: goreleaser/goreleaser:latest
39+
script: [goreleaser release --clean]

.golangci.yaml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
version: "2"
2+
3+
run:
4+
timeout: 5m
5+
go: "1.23"
6+
7+
linters:
8+
default: none
9+
enable:
10+
- errcheck
11+
- gosec
12+
- govet
13+
- ineffassign
14+
- staticcheck
15+
- unused
16+
- revive
17+
- misspell
18+
settings:
19+
revive:
20+
rules:
21+
- name: var-naming
22+
- name: error-return
23+
- name: error-strings
24+
- name: receiver-naming
25+
gosec:
26+
excludes:
27+
- G304 # file inclusion via variable: config/report paths are user-supplied by design
28+
- G402 # InsecureSkipVerify: behind opt-in --insecure flag with stderr warning
29+
exclusions:
30+
rules:
31+
- path: _test\.go
32+
linters: [errcheck, gosec]
33+
34+
formatters:
35+
enable:
36+
- gofmt
37+
- goimports
38+
settings:
39+
goimports:
40+
local-prefixes:
41+
- github.com/RandomCodeSpace/qctx

0 commit comments

Comments
 (0)