Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
711f65d
test(telemetry): establish RED version-one contract baseline
seonghobae Sep 24, 2026
4606184
experiment: add explicit bounded telemetry bootstrap
seonghobae Sep 24, 2026
3a5913d
experiment: inject exporter failures and exercise safe Ports
seonghobae Sep 24, 2026
199a258
experiment: bound metric names and label vocabulary
seonghobae Sep 24, 2026
d361b2c
experiment: preserve W3C trace identity without baggage
seonghobae Sep 24, 2026
11910d0
experiment: validate real Collector ingress with hostile OTLP requests
seonghobae Sep 24, 2026
8516cbd
experiment: export through authenticated Collector with explicit CA
seonghobae Sep 24, 2026
937c97b
chore: base telemetry implementation on owner repository
seonghobae Sep 24, 2026
a06550c
experiment: prove bounded queue loss and recovery
seonghobae Sep 24, 2026
f4853d6
feat: expose shared trace provider for framework instrumentation
seonghobae Sep 24, 2026
9128608
experiment: route only classified security records to SIEM canary
seonghobae Sep 24, 2026
4bfd2d5
feat: validate security OTLP and persist normalized outbox
seonghobae Sep 24, 2026
b566361
fix: prevent automatic exception payload in spans
seonghobae Sep 24, 2026
c8c0a6c
fix: keep raw span and request path outside product Port
seonghobae Sep 24, 2026
c66922a
test: validate production Collector template with pinned image
seonghobae Sep 24, 2026
c56ba8e
docs: define telemetry ownership and degraded delivery contract
seonghobae Sep 24, 2026
3c8382a
fix: report shutdown failures and close remaining providers
seonghobae Sep 24, 2026
dedf241
feat: admit bounded source locations without traversal
seonghobae Sep 24, 2026
7aa0e0a
test: decode actual SDK security log OTLP encoding
seonghobae Sep 24, 2026
4adb421
fix: reject huge numeric fields without overflow
seonghobae Sep 24, 2026
3ee2cce
ci: run shared telemetry contracts on each PR
seonghobae Sep 24, 2026
0a26c2a
Add authenticated durable security telemetry receiver
seonghobae Sep 24, 2026
409df96
Initialize security outbox on each access path
seonghobae Sep 24, 2026
df1a271
Verify durable Collector security delivery through outage
seonghobae Sep 24, 2026
f99bec4
fix(collector): keep security events out of operational logs
seonghobae Sep 24, 2026
1503c57
fix(collector): admit only versioned operational logs
seonghobae Sep 24, 2026
bbfef69
feat(telemetry): require explicit SIEM acknowledgement before outbox …
seonghobae Sep 24, 2026
5a9e405
Bound TLS and HTTP admission for security receiver
seonghobae Sep 24, 2026
349ed0c
Validate bearer tokens before constructing OTLP headers
seonghobae Sep 24, 2026
a41a8bd
Prepare reviewed exact-source telemetry release artifacts
seonghobae Sep 24, 2026
8158091
Ship validated Collector configuration with release artifacts
seonghobae Sep 24, 2026
848ed09
test(telemetry): verify retry and timeout isolation
seonghobae Sep 26, 2026
47615fa
fix(telemetry): bound security receiver request lifetime
seonghobae Sep 26, 2026
6af2a93
fix(security): close failed SIEM responses and verify early size reje…
seonghobae Sep 26, 2026
cd3d8a6
fix(security): reject ambiguous receiver headers
seonghobae Sep 26, 2026
9054639
fix(security): reject ambiguous SIEM acknowledgements
seonghobae Sep 26, 2026
546de0c
fix(ci): reject stale telemetry release lock
seonghobae Sep 26, 2026
3913d8f
fix(release): lock telemetry build backend
seonghobae Sep 26, 2026
833419c
docs: add telemetry discovery entry points
seonghobae Sep 26, 2026
bf891ed
fix(security): reject non-ASCII authorization headers
seonghobae Sep 27, 2026
d0acfd0
fix(security): close SQLite connections after event handoff
seonghobae Sep 27, 2026
82ab2a8
fix: reject empty receiver URL userinfo
seonghobae Sep 28, 2026
dc2224f
fix: reject SIEM URL userinfo before delivery
seonghobae Sep 28, 2026
c22ca4e
fix: expire acknowledged security replay rows during idle delivery
seonghobae Sep 28, 2026
9da68ea
test(security): require TLS 1.2 for HTTPS peers
seonghobae Sep 30, 2026
0dec365
docs: establish product technical gap baseline
seonghobae Sep 30, 2026
cc5cd63
docs: correct telemetry evidence and sender topology
seonghobae Sep 30, 2026
ab81a4d
docs: clarify SIEM acknowledgement and outbox boundary
seonghobae Sep 30, 2026
7343361
fix: bound telemetry wire payloads
seonghobae Oct 1, 2026
c5a582d
fix: bind shared metric and trace state
seonghobae Oct 1, 2026
88d3fda
fix: isolate span baggage context
seonghobae Oct 1, 2026
556bfcc
docs: bind telemetry gap evidence to hosted run
seonghobae Oct 1, 2026
80df3d3
docs: keep Pages README link in project scope
seonghobae Oct 1, 2026
fa15c18
test: reproduce SIEM outbox head-of-line rejection
seonghobae Oct 1, 2026
792eb2d
fix: retain permanently rejected security events
seonghobae Oct 1, 2026
2804eda
fix: continue after permanent SIEM rejection
seonghobae Oct 1, 2026
7c4a410
test: bind SIEM delivery and quarantine summary
seonghobae Oct 1, 2026
069be55
ci: drop checkout credentials before contract build
seonghobae Oct 1, 2026
4069556
docs: define fail-closed SIEM rejection contract
seonghobae Oct 1, 2026
7fd6c43
docs: record SIEM quarantine gap and evidence
seonghobae Oct 1, 2026
83284cc
test: expose telemetry admission and quarantine gaps
seonghobae Oct 1, 2026
6ab6aab
fix: bind telemetry admission and quarantine state
seonghobae Oct 1, 2026
0b324f9
test: expose type-confusion admission bypasses
seonghobae Oct 1, 2026
7ad433c
fix: reject telemetry type confusion
seonghobae Oct 1, 2026
9b81aa5
docs: record type-confusion repair evidence
seonghobae Oct 1, 2026
761ba3d
docs: bind repair evidence to hosted commits
seonghobae Oct 1, 2026
5c74077
test: expose case-sensitive trace extraction
seonghobae Oct 1, 2026
c2d3cce
fix: admit case-insensitive traceparent fields
seonghobae Oct 1, 2026
3aa86f2
test: expose traceparent duplicate sentinel bypass
seonghobae Oct 1, 2026
61de9c7
fix: make traceparent duplicate detection order-independent
seonghobae Oct 1, 2026
782445a
test: lock trace carrier edge cases
seonghobae Oct 1, 2026
d5e3b5d
docs(gap): reconcile exact-head hosted evidence
seonghobae Oct 2, 2026
78731bc
docs: add telemetry continuation and operations guides
seonghobae Oct 9, 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
53 changes: 53 additions & 0 deletions .github/workflows/prepare-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: Prepare telemetry release

on:
workflow_dispatch:

permissions:
contents: read

concurrency:
group: cwl-telemetry-release
cancel-in-progress: false

jobs:
prepare:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-24.04
timeout-minutes: 30
permissions:
contents: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.12.13'
- uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
with:
version: '0.12.3'
- run: uv sync --locked --group dev --no-install-project
- run: uv sync --locked --group dev --no-build-isolation
- run: uv run --no-sync pytest -q
- run: uv build --no-build-isolation
- run: tar -tzf dist/*.tar.gz | grep 'collector/production.yaml$' > /dev/null
- name: Create reviewable draft with exact-source artifacts
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
git fetch origin main
test "$(git rev-parse HEAD)" = "$GITHUB_SHA"
test "$(git rev-parse origin/main)" = "$GITHUB_SHA"
version="$(python -c 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])')"
tag="v${version}"
if git ls-remote --exit-code --tags origin "refs/tags/${tag}" >/dev/null; then
echo 'Version tag already exists' >&2
exit 1
fi
cp collector/production.yaml dist/cwl-otelcol-production.yaml
(cd dist && sha256sum ./*.whl ./*.tar.gz ./cwl-otelcol-production.yaml > SHA256SUMS)
gh release create "$tag" dist/*.whl dist/*.tar.gz dist/cwl-otelcol-production.yaml dist/SHA256SUMS \
--draft --target "$GITHUB_SHA" --title "$tag" \
--notes 'Draft release for independent review. Verify current-head checks, artifact hashes, and consumer migration before publication.'
33 changes: 33 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Telemetry contract

on:
pull_request:
push:
branches: [main]

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.repository }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
contract:
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.12.13'
- uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
with:
version: '0.12.3'
- run: uv sync --locked --group dev --no-install-project
- run: uv sync --locked --group dev --no-build-isolation
- run: uv run --no-sync pytest -q
- run: uv build --no-build-isolation
- run: tar -tzf dist/*.tar.gz | grep 'collector/production.yaml$' > /dev/null
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.venv/
.codegraph/
.pytest_cache/
.coverage
*.egg-info/
__pycache__/
dist/
graphify-out/
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.12.13
74 changes: 74 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# AGENTS.md

## Repository mission

`cwl-telemetry` is the optional canonical owner of the shared, explicit
OpenTelemetry runtime, Collector routing template, normalized security-event
receiver, and SIEM delivery contract. Product repositories retain domain
events, authorization decisions, audit truth, credential lifecycle, and
deployment ownership.

This repository is pre-release. An open PR or passing predecessor check is
Proposed evidence only; consumers must use a disabled feature flag or contract
test double until a protected-main build has an immutable version and digest.

## Required workflow

1. Fetch the current PR head and default-branch head before changing anything.
2. Review every open PR thread and exact-head check. Preserve concurrent work;
use ordinary descendant commits only—never force-push or destructively
rebase.
3. Start behavioral changes with a failing test at the canonical writer.
4. Run the smallest relevant test first, then the complete locked gate:
`uv sync --locked --group dev --no-install-project`,
`uv sync --locked --group dev --no-build-isolation`, and
`uv run --no-sync pytest -q`.
5. Build with `uv build --no-build-isolation` and verify the source
distribution contains `collector/production.yaml`.
6. Update `CHANGELOG.md` and
`docs/product-technical-gap-baseline.md` with exact revision and workflow
evidence. Do not convert Proposed decisions to Accepted from documentation.
7. Keep the PR Draft until current-head Checks are terminal green and an
independent reviewer approves it. Merge normally; publish only from the
protected default branch.

A hosted job with no executed steps and no log blob is runner evidence, not a
product regression. Record its job identity and continue safe work; do not
change source merely to retrigger infrastructure.

## Ownership and dependency rules

- Public product code depends only on an immutable released package or HTTPS
contract, never this branch, this repository's database, or copied source.
- `security_event_outbox` is private to the receiver/sender subsystem.
- The authenticated tenant is supplied by the receiver credential boundary,
never trusted from the OTLP record alone.
- The Collector admits TLS-authenticated OTLP and separates operational from
normalized security records.
- Only an exact event-ID acknowledgement marks delivery. Authenticated,
event-specific HTTP 400/422 rejection may quarantine; ambiguous failures stay
pending.
- Never log bearer tokens, raw security records, private keys, or request
headers. Use synthetic credentials and events in tests.
- Keep the runtime inert on import. Network, provider, thread, and process
creation require explicit bootstrap or CLI execution.

## Change discipline

Prefer the smallest causal change. Do not add a platform, control plane, shared
database, UI, or new provider abstraction without measured repeated demand and
an ADR. Preserve bounded inputs, finite vocabularies, explicit timeouts, TLS
1.2 minimum, private regular-file checks, exact acknowledgements, and durable
failure semantics.

Public modules, classes, functions, and methods require docstrings. Tests must
cover hostile boundaries and failure paths, including replay, conflicting
identity, mixed tenant, slow request, TLS failure, redirect, malformed
acknowledgement, restart, capacity exhaustion, and quarantine behavior.

## Evidence and handoff

`ARCHITECTURE.md` is the context and invariant authority.
`docs/security-operability.md` is the operator and incident authority.
`docs/product-technical-gap-baseline.md` is the live PRD/TRD/Gap status.
`CLAUDE.md` is a concise entry point and must not duplicate these contracts.
92 changes: 92 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Architecture

Status: Proposed while PR #1 remains unmerged and unreleased.

## Responsibility boundary

The Telemetry subdomain contains four bounded contexts:

| Bounded context | Responsibility | Owned interface/data |
| --- | --- | --- |
| Runtime Bootstrap | Explicit, inert SDK configuration and bounded product-facing Ports | `TelemetryConfig`, `TelemetryEvent`, `TelemetryRuntime` |
| Signal Routing | Authenticated OTLP admission and operational/security separation | `collector/production.yaml` |
| Security Normalization | Tenant-bound schema-v1 validation and durable idempotent admission | HTTPS `/v1/logs`; private `security_event_outbox` |
| Security Delivery | Bounded handoff to an operator-approved SIEM gateway | HTTPS `/v1/security-events`; exact acknowledgement |

Product bounded contexts are upstream customers. They own Ubiquitous Language,
domain event truth, authorization, authoritative audit records, and retention
decisions. This repository supplies an Anti-Corruption Layer to OpenTelemetry
and SIEM protocols; transport never becomes product truth.

## Context map

```mermaid
flowchart TD
Product["Product context"] -->|released SDK Port| Runtime["Runtime Bootstrap"]
Runtime -->|authenticated OTLP| Router["Signal Routing"]
Router -->|schema-v1 security logs| Normalizer["Security Normalization"]
Normalizer -->|private durable rows| Delivery["Security Delivery"]
Delivery -->|approved HTTPS contract| SIEM["SIEM gateway"]
```

No consumer may read the outbox, import a temporary branch, or share Collector
credentials. Before an immutable release, consumers use a disabled feature flag
or a contract test double.

## Domain model and invariants

- `TelemetryConfig` is a validated Value Object. Receiver configuration is
HTTPS-only, bearer-authenticated, and bounded.
- `TelemetryEvent` is a product-facing Value Object with finite names,
purposes, classifications, kinds, and attributes.
- A normalized security event is the aggregate admitted under one
authenticated tenant and one stable event ID.
- `security_event_outbox` is the aggregate store. State 0 is pending, state 1
is exactly acknowledged, and state 2 is quarantined after an authenticated
event-specific permanent rejection.
- Equal retries are idempotent. Reuse of an event ID with different content is
rejected.
- Ambiguous network, TLS, redirect, HTTP, or acknowledgement failure cannot
advance delivery state.
- Importing `cwl_telemetry` creates no provider, thread, socket, or process.
- All wire inputs, queues, label vocabularies, batches, counters, request
bodies, and deadlines are bounded.

SQLite is deliberately private and minimal. The receiver and scheduled sender
are the only writers. If measured concurrency outgrows this boundary, first
scale one receiver/outbox per tenant; adopt a new durable service only through
an ADR and migration contract.

## Runtime and deployment topology

The product explicitly creates isolated providers. The Collector receives OTLP
over TLS with bearer authentication, routes operational logs/traces/metrics to
the configured backend, and serializes security records to the tenant-bound
normalizer. The normalizer commits before acknowledging the Collector. A
separate operator-scheduled sender attempts one bounded batch and marks only
exactly acknowledged rows delivered.

The production template requires a persistent `/var/lib/otelcol` volume and
mounted credentials. Backend and security-consumer destinations are deployment
inputs; template presence is not proof that either destination is safe or
deployed.

## Failure scenes

| Scene | Required behavior |
| --- | --- |
| SDK exporter unavailable | Product work continues; bounded drop/failure accounting remains observable |
| Collector restarts | Persistent queue recovers without route mixing |
| Receiver sees a slow or malformed client | One absolute request deadline and bounded body fail closed |
| Duplicate event arrives | Equal content is replay-safe; conflicting content is rejected |
| SIEM is unavailable or redirects | Row remains pending and credential is not forwarded |
| SIEM rejects one event with exact 400/422 document | Row becomes quarantined; later rows may proceed; exit status requires operator attention |
| Process stops after remote acceptance but before local mark | Idempotency key permits safe replay |
| Outbox reaches capacity | Receiver returns unavailable; no record is silently overwritten |

## Release boundary

Acceptance requires terminal exact-head contract/security checks, independent
approval, normal merge to protected `main`, immutable artifacts and hashes,
and a consumer parity test against the released interface. Local builds,
predecessor checks, Draft releases, or branch URLs do not satisfy this boundary.
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Changelog

All notable changes to this unreleased package are recorded here.

## Unreleased

### Added

- Add contributor, architecture, and security/operability continuation guides
that preserve the telemetry owner boundary, exact-head evidence rules, and
fail-closed recovery procedures.

### Fixed

- Prevent reserved security event names from bypassing the durable security
route and export the same immutable attribute snapshot that admission checked.
- Make trace sampling and span limits explicit, and reject an ambient global SDK
disable instead of silently returning a no-op runtime.
- Match inbound W3C `traceparent` field names without case sensitivity and
reject ambiguous duplicates.
- Require an exact event-bound JSON Boolean rejection before quarantine and
count pending plus quarantined rows against the same outbox capacity.
- Reject operational event names longer than 128 characters before export.
- Bound trace and log exports to 16 records and remove inherited baggage and
TraceState so worst-case admitted batches fit the production Collector's
65,536-byte ingress limit while preserving trace identity.
- Reject counter increments whose cumulative canonical label-series total would
exceed the nonnegative signed 64-bit OTLP wire range; repeated handles share
the same synchronized accounting.
18 changes: 18 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# CLAUDE.md

Read and follow `AGENTS.md` before changing this repository.

The authoritative continuation order is:

1. `docs/product-technical-gap-baseline.md` for PRD/TRD, exact evidence, and
open commercialization Gaps;
2. `ARCHITECTURE.md` for bounded contexts, ports, owned data, and invariants;
3. `docs/security-operability.md` for deployment, recovery, and incident
procedures;
4. the current PR head, review threads, and workflow jobs for live state.

Do not treat this pre-release branch as a dependency. Do not force-push, copy
the source into consumers, read the private outbox cross-service, or claim a
release/deployment from local tests. Behavioral work begins with a failing
test; documentation-only work must still reconcile the live baseline and
CHANGELOG.
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
recursive-include collector *.yaml
Loading
Loading