.github/workflows/ci.yml:
- Go version: 1.22 -> 1.23.4 (matches go.mod's 'go 1.23.0' declaration).
- Split into four jobs with explicit names:
* test-backend: go vet + go build + go test
* scan-backend: staticcheck + govulncheck (installed from pinned tags)
* test-frontend: npm ci + eslint + tsc --noEmit + next build
* gitleaks: full-history secret scan on every PR
- Branches triggered: master + main + develop (master is the repo
default; the previous workflow only triggered on main/develop and
would never have run on the repo's actual PRs).
- actions/checkout@v4, actions/setup-go@v5, actions/setup-node@v4.
- Concurrency group cancels stale runs on the same ref.
- Node and Go caches enabled for faster CI.
.gitleaks.toml (new):
- Extends gitleaks defaults.
- Custom rule 'explorer-legacy-db-password-L@ker' keeps the historical
password pattern L@kers?\$?2010 wedged in the detection set even
after rotation, so any re-introduction (via copy-paste from old
branches, stale docs, etc.) fails CI.
- Allowlists docs/SECURITY.md and CHANGELOG.md where the string is
cited in rotation context.
backend/staticcheck.conf (new):
- Enables the full SA* correctness set.
- Temporarily disables ST1000/1003/1005/1020/1021/1022, U1000, S1016,
S1031. These are stylistic/cosmetic checks; the project has a long
tail of pre-existing hits there that would bloat every PR. Each is
commented so the disable can be reverted in a dedicated cleanup.
Legit correctness issues surfaced by staticcheck and fixed in this PR:
- backend/analytics/token_distribution.go: 'best-effort MV refresh'
block no longer dereferences a shadowed 'err'; scope-tight 'if err :='
used for the subsequent QueryRow.
- backend/api/rest/middleware.go: compressionMiddleware() was parsing
Accept-Encoding and doing nothing with it. Now it's a literal
pass-through with a TODO comment pointing at gorilla/handlers.
- backend/api/rest/mission_control.go: shadowed 'err' from
json.Unmarshal was assigned to an ignored outer binding via
fmt.Errorf; replaced with a scoped 'if uerr :=' that lets the RPC
fallback run as intended.
- backend/indexer/traces/tracer.go: best-effort CREATE TABLE no longer
discards the error implicitly.
- backend/indexer/track2/block_indexer.go: 'latestBlock - uint64(i) >= 0'
was a tautology on uint64. Replaced with an explicit
'if uint64(i) > latestBlock { break }' guard so operators running
count=1000 against a shallow chain don't underflow.
- backend/tracing/tracer.go: introduces a local ctxKey type and two
constants so WithValue calls stop tripping SA1029.
Verification:
- go build ./... clean.
- go vet ./... clean.
- go test ./... all existing tests PASS.
- staticcheck ./... clean except for the SA1029 hits in
api/middleware/auth.go and api/track4/operator_scripts_test.go,
which are resolved by PR #4 once it merges to master.
Advances completion criterion 4 (CI in good health).
backend/api/middleware/context.go (new):
- Introduces an unexported ctxKey type and three constants
(ctxKeyUserAddress, ctxKeyUserTrack, ctxKeyAuthenticated) that
replace the bare string keys 'user_address', 'user_track', and
'authenticated'. Bare strings trigger go vet's SA1029 and collide
with keys from any other package that happens to share the name.
- Helpers: ContextWithAuth, UserAddress, UserTrack, IsAuthenticated.
- Sentinel: ErrMissingAuthorization replaces the misuse of
http.ErrMissingFile as an auth-missing signal. (http.ErrMissingFile
belongs to multipart form parsing and was semantically wrong.)
backend/api/middleware/auth.go:
- RequireAuth, OptionalAuth, RequireTrack now all read/write via the
helpers; no more string literals for context keys in this file.
- extractAuth returns ErrMissingAuthorization instead of
http.ErrMissingFile.
- Dropped now-unused 'context' import.
backend/api/track4/operator_scripts.go, backend/api/track4/endpoints.go,
backend/api/rest/features.go:
- Read user address / track via middleware.UserAddress() and
middleware.UserTrack() instead of a raw context lookup with a bare
string key.
- Import 'github.com/explorer/backend/api/middleware'.
backend/api/track4/operator_scripts_test.go:
- Four test fixtures updated to seed the request context through
middleware.ContextWithAuth (track 4, authenticated) instead of
context.WithValue with a bare 'user_address' string. This is the
load-bearing change that proves typed keys are required: a bare
string key no longer wakes up the middleware helpers.
backend/api/middleware/context_test.go (new):
- Round-trip test for ContextWithAuth + UserAddress + UserTrack +
IsAuthenticated.
- Defaults: UserTrack=1, UserAddress="", IsAuthenticated=false on a
bare context.
- TestContextKeyIsolation: an outside caller that inserts
'user_address' as a bare string key must NOT be visible to
UserAddress; proves the type discipline.
- ErrMissingAuthorization sentinel smoke test.
Verification:
- go build ./... clean.
- go vet ./... clean (removes SA1029 on the old bare keys).
- go test ./api/middleware/... ./api/track4/... ./api/rest/... PASS.
Advances completion criterion 3 (Auth correctness).
backend/api/rest/server.go:
- NewServer() now delegates to loadJWTSecret(), which:
- Rejects JWT_SECRET < 32 bytes (log.Fatal).
- Requires JWT_SECRET when APP_ENV=production or GO_ENV=production.
- Generates a 32-byte crypto/rand ephemeral secret in dev only.
- Treats rand.Read failure as fatal (removes the prior time-based
fallback that was deterministic and forgeable).
- Default Content-Security-Policy rewritten:
- Drops 'unsafe-inline' and 'unsafe-eval'.
- Drops private CIDRs (192.168.11.221:854[5|6]).
- Adds frame-ancestors 'none', base-uri 'self', form-action 'self'.
- CSP_HEADER is required in production; fatal if unset there.
backend/api/rest/server_security_test.go (new):
- Covers the three loadJWTSecret() paths (valid, whitespace-trimmed,
ephemeral in dev).
- Covers isProductionEnv() across APP_ENV / GO_ENV combinations.
- Asserts defaultDevCSP contains no unsafe directives or private CIDRs
and includes the frame-ancestors / base-uri / form-action directives.
scripts/*.sh:
- Removed 'L@kers2010' default value from SSH_PASSWORD / NEW_PASSWORD in
7 helper scripts. Each script now fails with exit 2 and points to
docs/SECURITY.md if the password isn't supplied via env or argv.
EXECUTE_DEPLOYMENT.sh, EXECUTE_NOW.sh:
- Replaced hardcoded DB_PASSWORD='L@ker$2010' with a ':?' guard that
aborts with a clear error if DB_PASSWORD (and, for EXECUTE_DEPLOYMENT,
RPC_URL) is not exported. Other env vars keep sensible non-secret
defaults via ${VAR:-default}.
README.md:
- Removed the hardcoded Database Password / RPC URL lines. Replaced with
an env-variable reference table pointing at docs/SECURITY.md and
docs/DATABASE_CONNECTION_GUIDE.md.
docs/DEPLOYMENT.md:
- Replaced 'PASSWORD: SSH password (default: L@kers2010)' with a
required-no-default contract and a link to docs/SECURITY.md.
docs/SECURITY.md (new):
- Full secret inventory keyed to the env variable name and the file that
consumes it.
- Five-step rotation checklist covering the Postgres role, the Proxmox
VM SSH password, JWT_SECRET, vendor API keys, and a gitleaks-based
history audit.
- Explicit note that merging secret-scrub PRs does NOT invalidate
already-leaked credentials; rotation is the operator's responsibility.
Verification:
- go build ./... + go vet ./... pass clean.
- Targeted tests (LoadJWTSecret*, IsProduction*, DefaultDevCSP*) pass.
Advances completion criterion 2 (Secrets & config hardened). Residual
leakage from START_HERE.md / LETSENCRYPT_CONFIGURATION_GUIDE.md is
handled by PR #2 (doc consolidation), which deletes those files.
- Remove committed Go binaries:
backend/bin/api-server (~18 MB)
backend/cmd (~18 MB)
backend/api/rest/cmd/api-server (~18 MB)
- Remove scratch / build output dirs from the repo:
out/, cache/, test-results/
- Extend .gitignore to cover these paths plus playwright-report/
and coverage/ so they don't drift back in.
Total artifact weight removed: ~54 MB of binaries + small scratch files.
- Introduced a new Diagnostics struct to capture transaction visibility state and activity state.
- Updated BuildSnapshot function to return diagnostics alongside snapshot, completeness, and sampling.
- Enhanced test cases to validate the new diagnostics data.
- Updated frontend components to utilize the new diagnostics information for improved user feedback on freshness context.
This change improves the observability of transaction activity and enhances the user experience by providing clearer insights into the freshness of data.
- Updated branding from "SolaceScanScout" to "Solace" across various files including deployment scripts, API responses, and documentation.
- Changed default base URL for Playwright tests and updated security headers to reflect the new branding.
- Enhanced README and API documentation to include new authentication endpoints and product access details.
This refactor aligns the project branding and improves clarity in the API documentation.
- Added new compliant tokens including Tether EUR, Pound Sterling, and others to the DUAL_CHAIN_TOKEN_LIST.
- Updated version in the token list configuration to 1.2.
- Enhanced Nginx configuration to support token-aggregation API and serve token list and network configurations from specified paths.
Co-authored-by: Cursor <cursoragent@cursor.com>