Commit Graph
10 Commits
Author SHA1 Message Date
jcoffey-dev c60028aad1 Move the Go toolchain pins to 1.26, in CI and in every image
Two Dependabot PRs are stuck behind the same number.

#35 raises the go directive to 1.26.0 in six modules, because
golang.org/x/crypto v0.56.0 requires it -- x/crypto tracks the two most
recent Go releases and 0.56 dropped 1.25. A module that says 1.26 cannot
be built by the 1.25 this repository pins in two places, so that PR
fails every Go job.

#29 raises actions/setup-go to v7, which sets GOTOOLCHAIN=local. With
that set, `go install golang.org/x/vuln/cmd/govulncheck@latest` cannot
quietly fetch a newer toolchain, and stops with

  golang.org/x/[email protected] requires go >= 1.26.0 (running go 1.25.14)

Under setup-go v5 the same install succeeded by downloading 1.26 behind
our backs, which is its own reason to be on 1.26 deliberately instead.

So: security-scan's go-version and all eight Dockerfiles move together,
1.25 -> 1.26. Nothing else needs to. A newer toolchain builds an older
directive happily, so this stands on its own before #35 lands, and the
go.mod files stay where they are here.

Checked by building rather than by reading: the api and ingest images
both build on golang:1.26-alpine, and api, ingest and enterprise still
`go build ./...` clean against their existing 1.25 directives.
2026-09-10 09:54:45 -07:00
jcoffey-dev df6f9d049f Point the Sponsor button at the current GitHub username
The account behind it was renamed from LINUXexpert-org to jcoffey-dev,
and GitHub does not redirect the old name: github.com/sponsors/
LINUXexpert-org answers 404 while the new one answers 200. So the
Sponsor button on this repository has been leading nowhere.

Worth fixing rather than leaving to redirect, because a released
username can be registered by anyone -- a stale link stops being a dead
end and starts being someone else's page.
2026-09-10 09:17:02 -07:00
jcoffey-dev b7f99b49f2 Take grpc to 1.83.2 across the nine modules that carry it
GHSA-2v4p-qf9q-27wj is a panic in gRPC-Go's xDS routing interceptor: a
request arriving with neither `:authority` nor `Host` indexes an empty
slice, the per-RPC goroutine does not recover, and the process dies.
High, and nine alerts, because nine go.mod files pin the same version --
eight directly, terraform indirectly.

Nothing here was reachable. The interceptor is installed by
`xds.NewGRPCServer`, which this repo never calls: the one production
server is `grpc.NewServer(grpc.Creds(...))` in ingest/internal/grpcserver
and the only other is a plain one in a searchclient test. That is also
why security-scan has been green throughout -- govulncheck reports on
reachability and found nothing on 1.83.1, while Dependabot reports on
version ranges and found nine. Both were right.

Taken anyway: it is a patch release, and the next advisory in this
dependency may well land somewhere we do reach.

`go mod tidy` carried the indirect requirements grpc 1.83.2 asks for --
x/net, x/text, x/sys and friends. No CI job builds or tests Go here, so
all nine modules were built locally and api, ingest and enterprise
tested with -count=1, since a cached pass would not have exercised the
new version.

The dependabot.yml is the other half. There was no config, so nothing
opened a PR against any of this. Go majors stay out of the group, being
import path changes rather than bumps.
2026-09-10 09:01:27 -07:00
Coffey Labs 6a17fa1562 Update GitHub Sponsors username in FUNDING.yml
Signed-off-by: Coffey Labs <[email protected]>
2026-09-05 00:51:06 -07:00
jcoffey-dev 7fabc6a067 Build the Phase 8 conformance corpus
The design argues the conformance suite is the specification and should
be built before either implementation, since two hand-written
implementations of one language diverge unless something shared pins
them. This is that suite: 38 cases in /processing, a language-neutral
top-level directory for the same reason /proto is one -- the Rust agent
and the Go ingest tier both consume the definition and neither owns it.

Nothing executes the cases, because neither implementation exists. A
stdlib-only validator checks the corpus stays well-formed and runs in
CI: known actions, addressable fields, compilable patterns, names
matching filenames, and no case depending on record_id, which is
withheld so the question of whether an ingest-side rule can see one
stays open. The validator was checked against seven deliberately broken
cases before being trusted, since "38/38 valid" means nothing from a
validator that cannot fail.

Writing the cases first has already paid for itself twice.

It forced two determinism decisions the prose had left vague, both of
which a conformance suite cannot avoid answering. Sampling is
counter-based rather than random: random is statistically nicer and
impossible to assert on. Windows are measured on record timestamps
rather than wall-clock, which makes replay deterministic and, not
incidentally, makes backfill behave correctly where a wall-clock window
would not.

And it made the missing aggregate_count answer concrete. The design
does not say what that action emits, or what a query not expecting a
synthetic record sees. Rather than invent one by writing cases, the
validator rejects any case using it, so the design question has to be
answered before the behaviour can be frozen by accident.

The corpus includes the acceptance case from real measured data: the
two processes that account for roughly 60% of a real workstation's
journal volume, and the one kernel message worth keeping.

Signed-off-by: John Coffey <[email protected]>
2026-09-04 20:19:51 -07:00
jcoffey-dev e8b6a8bc2e Answer 404 for unrouted paths, and keep the route lists honest
web/nginx.conf ended its try_files chain in an unconditional /200.html, so
every path the site does not have -- /wp-login.php, /.env, a typo'd inbound
link -- came back as the SPA shell with a success status. It now answers 404,
which needs nginx to know which routes exist: most it infers from the build
output, but dynamic routes and ones that never opted into prerendering have no
file on disk and are listed by hand.

Those hand-maintained lists drift, and the drift is invisible until it ships:
vite dev and npm run preview route from the client manifest and never read
nginx.conf, so a new dynamic route works everywhere a developer would look and
404s in production. hack/check-web-routes.sh compares the lists against
web/src/routes, and a workflow runs it. Its own workflow rather than another
job on license-compliance.yml, which already carries one unrelated check.

Also turns absolute_redirect off. With nginx's default the trailing-slash
canonicaliser reconstructs the origin from its own listen port, so a request
for https://demo.cairnobs.org/settings/ was answered with
Location: http://127.0.0.1:3000/settings -- the container's internal address,
unreachable from the client, and downgraded to http on the way. Verified by
curl against the built image; it was latent here before the canonicaliser
existed too, through the directory redirect on /dev.
2026-08-28 15:55:28 -07:00
jcoffey-dev 81ee47b1cd ci: fix the security scan, which has failed on every push
Two unrelated causes, plus one that hid the others.

govulncheck: setup-go used go-version-file, so it installed exactly what
each go.mod pins -- `go 1.25.0` -- and then reported 28 CVEs in that
release's standard library (crypto/x509 quadratic name-constraint
parsing, GO-2025-4007, and friends), all fixed in 1.25.3. None of it
described anything we ship: every Dockerfile builds FROM
golang:1.25-alpine, a floating tag that resolves to the newest 1.25.x,
so the binaries already had the fixes. The go directive is a minimum
language version, not a statement about which toolchain to audit with.
Track the floating 1.25 line instead, and the scan matches production.
Confirmed by running govulncheck against a patched toolchain locally:
deploy/operator reports 0 vulnerabilities and exits 0.

cargo-deny: RUSTSEC-2024-0384, `instant` is unmaintained. A maintenance
advisory rather than a vulnerability -- no CVE, nothing to patch -- and
it arrives transitively via tantivy 0.22.1 -> measure_time 0.8.3, so it
cannot be dropped without moving off the pinned Tantivy. The advisory's
substance does not apply here anyway: instant papers over
std::time::Instant being missing on wasm, and search builds native musl.
Ignored in search/deny.toml with that reasoning recorded and a note to
delete the entry at the next Tantivy upgrade rather than let it ossify.

Both matrices now set fail-fast: false. Only two of the twelve jobs
actually failed; the other nine were cancelled, which made a two-cause
failure look like a total collapse and hid every finding but the first.
2026-08-22 19:22:42 -07:00
jcoffey-dev 13cf9a30cb Rebrand: Sentry -> Cairn OBS
Full rebrand across cosmetic branding, code identifiers, and
infrastructure/data-plane naming, using the supplied Cairn OBS logo
package. Cosmetic: favicon/logo swap (also closes a stale license-audit
finding -- the old favicon was SvelteKit's unreplaced scaffold logo),
new centered welcome landing page, larger/legible sidebar logo, page
titles, CLAUDE.md/README/docs prose.

Code identifiers: Go module path github.com/sentry/sentry ->
github.com/cairnobs/cairnobs across all 13 modules and ~91 files (protoc
regenerated); Rust crates sentry-agent/sentry-parser/sentry-search ->
cairnobs-*; CLI sentryctl -> cairnobsctl; Terraform provider fully
renamed (sentry_dashboard etc. -> cairnobs_dashboard, provider type,
env vars); every session/auth cookie name; agent config paths and
Windows service identity.

Deliberately preserved: the gRPC wire protocol's protobuf packages
(sentry.logs.v1, sentry.agent.v1) and their Go import directory
(proto/sentry/...) -- renaming the wire-level package would break every
currently-deployed agent binary (confirmed two real hosts, including
mail.inbuxa.com, are actively streaming through this exact contract)
until rebuilt and redeployed in lockstep with an ingest cutover. Only
the Go module path wrapping the generated code changes.

Infrastructure: every docker-compose container name (root and three
component-level compose files); the Helm chart (directory, Chart.yaml,
named-template helpers, all templates, values.yaml image repos);
Kubernetes Operator (CRD group sentry.io -> cairnobs.io, both CRD YAML
files, Go identifiers, RBAC markers); the coupled enterprise/tenantcrd
package. Caught and fixed real path-coupling bugs along the way: the
Helm chart's search/ingest volume mounts and the dev-only-credential
detection constant vs. docker-compose.yml's literal values had to move
together or a security warning would have silently stopped firing.

Data plane: Postgres database sentry_metadata -> cairnobs_metadata and
role sentry -> cairnobs; ClickHouse database sentry -> cairnobs; Kafka
topic sentry.logs.raw -> cairnobs.logs.raw and its consumer groups.
Source-level defaults, docker-compose.yml, and every migrate.sh/
provision script default updated together; already-applied migration
files left untouched per this repo's immutable-migration convention.

Verified at every layer: all 13 Go modules build/vet/test clean, both
Rust workspaces (agent, search) build/clippy/test clean, npm run check/
build clean, docker compose config validates on all four compose files.
Live-verified against a real docker stack multiple times through this
work, including a final fresh-volume run confirming the actual renamed
Postgres database/role, ClickHouse database, and Kafka topic all work
end to end with a real login and query, zero console errors.
2026-08-21 20:53:32 -07:00
jcoffey-dev 4b5dae5879 Add local login, agent extra log paths, IPv4/IPv6 metrics; remediate security audit findings
This is a large squashed commit covering two batches of prior uncommitted
work plus a full security-audit remediation pass, kept together because
go.mod/go.sum and several shared files (main.go, handler.go) were touched
by both and splitting risked non-building intermediate commits.

Features (built earlier, previously uncommitted):
- Local username/password login for single-tenant deployments with no
  SSO configured (api/localauth, alerting/internal/sessioncheck,
  sentryctl users, web/src/routes/login, metadata migrations 0040/0041).
- Remotely-editable additional log file paths for agents, on top of
  their existing primary source (api/agents, agent/sentry-agent
  extra-file-path diffing, web agent config UI).
- IPv4/IPv6 addresses reported alongside other host system metrics.

Security audit remediation (this pass, all live-verified in production):
- Critical: block ClickHouse SSRF table functions (url/remote/file/s3/...)
  in the raw-SQL query escape hatch.
- High: deny sensitive paths and require Admin to add agent
  extra_file_paths (Editor could previously point an agent at /etc/shadow
  or an SSH key); alerting webhook targets now validate against
  internal/metadata/loopback addresses, both at creation and send time;
  alerting's session middleware now enforces an Editor+ floor on
  mutating requests instead of "any authenticated session"; bumped
  goxmldsig to close a SAML signature-verification bypass (GO-2026-4753).
- Medium: per-IP login rate limiting; security response headers
  (HSTS/CSP/nosniff/X-Frame-Options/Referrer-Policy/Permissions-Policy)
  on web/nginx.conf; a DevCredentialWarnings check in every Go service's
  config loader, logging loudly at startup if a deployment is still on
  docker-compose.yml's literal dev-only credentials; dependency bumps
  (golang.org/x/text, grpc, x/net, quick-xml, h2) across every affected
  Go module and both Rust crates, including a previously-uncovered x/net
  vulnerability in deploy/operator; a new security-scan.yml CI workflow
  running cargo-deny/govulncheck/npm-audit, mirroring the existing
  license-compliance.yml matrix shape.
- Low: removed sentryctl's plaintext --password flag (shell
  history/`ps` exposure) in favor of stdin and a --password-stdin flag
  for reset-password's optional specific-password path; a dummy bcrypt
  comparison closes a login response-time username-enumeration
  side-channel.
2026-08-18 23:53:20 -07:00
jcoffey-dev 661568085e Phase 6: license-compliance audit and enterprise/ relicensing to AGPLv3
Full dependency inventory across Rust/Go/npm plus Docker base images
and vendored assets (776 rows, 502 unique deps), classified against
AGPLv3 compatibility with real citations rather than assumptions.
enterprise/ relicensed from its commercial-license stub to AGPLv3,
matching core -- the one real flag (Redpanda's BSL 1.1) was evaluated
against primary sources and accepted as-is rather than triggering a
broker swap. CI enforcement wired up (.github/workflows/license-
compliance.yml, this repo's first CI workflow), a root LICENSE file
added, and every doc/comment referencing the old commercial-license
boundary updated to describe it as architectural only.

See /docs/compliance/ for the full report, inventory, and policy.
2026-08-16 18:03:32 -07:00