Repository navigation
batch/2026-06-20: status model, SSL/Docker checks, MCP OAuth, config-as-code (8 specs) - #85
Merged
Merged
Conversation
Specs for the genuine feature gaps surfaced by docs/competitors/maintenant.md, grounded in the current code: - todos/2026-06-20-01 SSL graduated expiry (warning/critical tiers) + whole-chain nearest-expiry & chain reporting - todos/2026-06-20-02 Docker restart-loop (crash-loop) detection - todos/2026-06-20-03 OAuth 2.1 authorization for the MCP endpoint - todos/2026-06-20-04 first-class StatusWarning (degraded-but-up) status — enabler that 01 and 02 depend on - ideas/2026-06-20-config-as-code declarative checks + Docker-label discovery Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Code-verified every claim in 2026-06-20-04 against the tree and folded in corrections: - checkerdef.Status has no Created (starts Running=2) - new finding: aggregation rollup tie-break (calculateDominantStatus) ranks by raw status number, so Warning=7 would mask outages — add Severity() helper + severity-aware tie-break (Decision D) - frontend wire string is split between "warning" and "degraded"; standardise on "degraded" + one shared statusStyle() util (Decision C); per-file table, plus two previously-missed components (status-timeline, check-summary-cards) - incident classifier early-returns before the visible-status update; warning needs a third path modelled on the display-only CheckStatusValidating - slack statusIntToString currently maps warning to "unknown" Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…odel Spec 04 reshaped per user answers to the open questions: - two statuses: Warning (live, value 8, "up but something to report") + Degraded (aggregated, value 7); aggregation promotes raw Warning -> rolled-up Degraded - availability: warning counts as up; incidents: warning neutral - constraint: amend 001 in place, widen results.status to (0..8) incl. the previously-missing 6 (error) - frontend: one shared statusStyle() util mapping both "warning" and "degraded" - record follow-on sub-decisions (values 7/8, rollup promotion rule, role of CheckStatusDegraded) and the five status->string sites found in review Specs 01 (SSL) and 02 (restart-loop) realigned: a live warning shows current status Warning; Degraded appears only in rolled-up history. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Resolve open questions in the 2026-06-20 todos and align ideas with the new Warning/Degraded status model. - ssl (-01): warningDays defaults to criticalDays (30); criticalDays stays 30 (docs recommend 7); checkdomain tiering is a follow-up. - docker (-02): Approach A heuristic MVP; loop => StatusWarning; minRestarts=3/window=120s; firm dependency on -04. - mcp-oauth (-03): embedded AS + DCR in scope (Phase 3); 4 unrecommended forks kept as explicit open questions with leanings. - ideas: flag stale enum/warn_days in check-interface as superseded; note Warning is incident-neutral in notification-channels & telegram specs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ng streak, no open/resolve)
…verity, incident-neutral, persistence
Embedded OAuth 2.1 AS for the MCP resource: discovery docs (RFC 9728/8414), authorize/token/register endpoints, PKCE S256, audience binding (RFC 8707), single-use codes, rotating refresh tokens, DCR (RFC 7591) with loopback redirect exception, and revocation on logout/PAT-revoke. Reuses the existing HS256 JWT signing key and user session. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
dash0 route /orgs/$org/oauth/consent renders the requested scope (read-only vs read-write) and posts approve/deny back to /api/v1/oauth/authorize via a native form so the access_token cookie rides along. Server handles deny with access_denied. Built from design-reference primitives (Card/Button/Alert); auth enforced by the parent org layout (401 -> login?returnTo). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…res) Table-driven tests (testify/require, t.Parallel): well-formed discovery docs; unauthenticated MCP request -> 401 with WWW-Authenticate resource_metadata pointer; missing/plain PKCE rejected; reused/expired auth code rejected; wrong/blocked redirect_uri rejected and loopback accepted; wrong aud rejected at the MCP gate; refresh rotation invalidates the prior token; mcp:read scope flows to claims; DCR public-vs-confidential. Cross-engine OAuth-repo parity (testOAuthRepos) runs under both SQLite and embedded Postgres. Also: lint fixes (RFC snake_case nolint, sentinel error renames, var naming, hugeParam pointers) and mock db.Service stubs for the new OAuth methods. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reframe the config-as-code idea around what SolidPing already ships
(export schema, idempotent upsert-by-slug import, sp CLI, secret
envelope + parameters table, check labels). The gap narrows to the
reconcile loop: delete-by-absence within a managed-label scope,
dry-run/diff, secret references (${env}/${param}), an sp apply verb,
and admin-gating. Resolves the five open questions against the code and
phases the work; demotes Docker-label discovery to an optional suggest
source.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Move specs/ideas/2026-06-20-config-as-code.md to specs/todos/2026-06-20-05-config-as-code.md (NN=05, next free for the day). Update the banner from "idea" to active spec and fix the sibling links to the ideas/ folder that the move would otherwise break. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…in gating
- Reconcile/plan engine (create/update/delete/unmanaged/rename) scoped by the
reserved solidping.io/managed=<manifest> label
- ApplyChecks service: dryRun (plan only), prune+managed-label+deletion-cap
delete-by-absence, never touches unmanaged checks
- Secret references ${env:NAME}/${param:KEY} resolved server-side; missing ref
is a hard error; plaintext-fallback emits a warning
- POST /checks/apply endpoint accepting JSON and YAML bodies
- Admin-gate apply, and retro-gate /checks/export + /checks/import to admin-only
- sp apply [-f] <manifest> [--dry-run] [--prune] [--force] [--yes]: computes a dry-run plan first, prints it, prompts before mutating unless --yes - sp checks export [--file] and sp checks import <file> [--dry-run] wrappers - client methods ApplyChecks/ExportChecks/ImportChecks (raw HTTP; apply sends the manifest bytes with a YAML/JSON content-type)
Adds table-driven coverage for the apply reconcile engine and resolves
pre-existing lint findings in the apply/CLI/client code from the prior
implementation commits.
Tests:
- plan computation (create/update/delete/unmanaged), dryRun mutates nothing
- delete-by-absence only with prune+managed-label+within-cap; cap refuses
oversized prune (force overrides); unmanaged checks never touched
- secret-ref resolution (${env}/${param}, missing -> error, plaintext
fallback -> warning); rename via previousSlug
- JSON and YAML bodies parse to the same plan (internal + HTTP)
- export->apply round-trip idempotence (apply of an export is no-op/update)
- admin-only gating on apply AND export/import (non-admin -> 403)
Lint: queryTrue/colSlug constants, checked json marshals, dropped unused
nolint directives and the unused rawRequestBytes status return.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The new "header stacks the action toolbar" test asserted no horizontal overflow on the whole document (documentElement.scrollWidth), which is tripped by unrelated page content (a chart that sizes differently in headless CI) rather than the header it is testing — failing all 3 CI attempts though it passes locally. Add a data-testid to the header container and scope the overflow check to that element. The header (flex-col title row + flex-wrap toolbar + truncating h1) cannot overflow its own width, and this still catches a real header regression. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Merged
fclairamb
added a commit
that referenced
this pull request
Jun 23, 2026
🤖 I have created a release *beep* *boop* --- ## [0.1.0](v0.0.0...v0.1.0) (2026-06-22) ### Features * add check type registry, sample configs, notification senders, and observability integrations ([eea049e](eea049e)) * batch — Warning/Degraded statuses, SSL/Docker check upgrades, MCP OAuth 2.1, config-as-code ([#85](#85)) ([936d830](936d830)) * batch spec implementations (dashboard UI, jobs, notifications, SaaS, perf) ([#78](#78)) ([fe003e4](fe003e4)) * bulk feature integration (discovery, web push, badges, webhooks, and more) ([#73](#73)) ([a976856](a976856)) * custom user-agent, refresh checks, vite plugin switch, CI updates ([#1](#1)) ([cc00858](cc00858)) * documentation site served at /docs (co-located in web/docs) ([#88](#88)) ([27d9ccd](27d9ccd)) * email check frontend (spec 03) ([#30](#30)) ([aebd106](aebd106)) * email inbox foundation via JMAP (spec 01) ([#24](#24)) ([0f3b0c1](0f3b0c1)) * email passive checks (spec 02) ([#27](#27)) ([ba5536f](ba5536f)) * **entitlements:** trim to MaxSSOUsers + MaxChecksPerMinute + status page history fixes ([#50](#50)) ([a007de0](a007de0)) * **entitlements:** trim to MaxSSOUsers + MaxChecksPerMinute, enforce both ([#49](#49)) ([d25cc5f](d25cc5f)) * group incident correlation (spec 04 backend v1) ([#31](#31)) ([1883986](1883986)) * **observability:** instrument hot path + add bench harness ([#60](#60)) ([c6604cc](c6604cc)) * **oncall:** searchable timezone dropdown + sidebar logo polish ([#46](#46)) ([4396898](4396898)) * per-IP HTTP rate limiting and concurrency limiting ([#59](#59)) ([f9cc273](f9cc273)) * soften HTTP rate limits with bounded queues + request timeout ([#63](#63)) ([025501b](025501b)) * SolidPing — distributed uptime monitoring platform ([eef4383](eef4383)) * **statuspages:** drag-and-drop resource reordering + dash conventions ([#41](#41)) ([cf910d4](cf910d4)) ### Bug Fixes * **deps:** update dependency i18next to v26 ([#26](#26)) ([d5d1b7e](d5d1b7e)) * **deps:** update dependency lucide-react to v1 ([#28](#28)) ([cdc8e8c](cdc8e8c)) * **deps:** update dependency react-i18next to v17 ([#29](#29)) ([13135d8](13135d8)) * **deps:** update dependency recharts to v3.8.1 ([#14](#14)) ([5d95a3b](5d95a3b)) * **deps:** update go dependencies (non-major) ([#16](#16)) ([2450f13](2450f13)) * **deps:** update go dependencies (non-major) ([#19](#19)) ([f842310](f842310)) * **deps:** update go dependencies (non-major) ([#37](#37)) ([c020eca](c020eca)) * **deps:** update go dependencies (non-major) ([#44](#44)) ([ff0bcd0](ff0bcd0)) * **deps:** update go dependencies (non-major) ([#52](#52)) ([2e3bc28](2e3bc28)) * **deps:** update go dependencies (non-major) ([#69](#69)) ([a65ed4c](a65ed4c)) * **deps:** update go dependencies (non-major) ([#77](#77)) ([a0920ff](a0920ff)) * **deps:** update go dependencies (non-major) to v1.4.2 ([#86](#86)) ([1eb7504](1eb7504)) * **deps:** update module github.com/aws/aws-sdk-go-v2/config to v1.32.18 ([#72](#72)) ([6406537](6406537)) * **deps:** update module github.com/aws/aws-sdk-go-v2/service/s3 to v1.101.0 ([#39](#39)) ([f9c9563](f9c9563)) * **deps:** update module github.com/go-webauthn/webauthn to v0.17.3 ([#45](#45)) ([593931a](593931a)) * **deps:** update module github.com/go-webauthn/webauthn to v0.17.4 ([#70](#70)) ([fca1c97](fca1c97)) * **deps:** update module github.com/ibm/sarama to v1.48.1 ([#47](#47)) ([93ccf3a](93ccf3a)) * **deps:** update module github.com/ibm/sarama to v1.48.2 ([#54](#54)) ([e84d868](e84d868)) * **deps:** update module github.com/ibm/sarama to v1.49.0 ([#64](#64)) ([fd61bd7](fd61bd7)) * **deps:** update module github.com/oapi-codegen/runtime to v1.4.1 ([#65](#65)) ([a3a3e9f](a3a3e9f)) * **deps:** update module github.com/prometheus/common to v0.67.5 ([#61](#61)) ([095dd6f](095dd6f)) * **deps:** update module github.com/slack-go/slack to v0.24.0 ([#75](#75)) ([6e86d5b](6e86d5b)) * **deps:** update module golang.org/x/sys to v0.44.0 ([#42](#42)) ([a245730](a245730)) * **deps:** update module golang.org/x/sys to v0.45.0 ([#67](#67)) ([49c3d90](49c3d90)) * **deps:** update module golang.org/x/term to v0.43.0 ([#43](#43)) ([4a934f1](4a934f1)) * **deps:** update module google.golang.org/grpc to v1.81.0 ([#36](#36)) ([1be183a](1be183a)) * **deps:** update module google.golang.org/grpc to v1.81.1 ([#55](#55)) ([6bfac2d](6bfac2d)) * status lifecycle improvements and created/running result handling ([#5](#5)) ([fc64c7d](fc64c7d)) * **status0:** white page header and de-duplicated footer ([#48](#48)) ([77506a7](77506a7)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
2 tasks done
fclairamb
added a commit
that referenced
this pull request
Jul 5, 2026
#105) ## Summary release-please's changelog only sees each squash-merge commit's own title/body. The v0.1.0 and v0.2.0 batch integration PRs (#73, #78, #85, #89) each bundled many independently-implemented, independently-audited specs behind one flattened changelog bullet, hiding most of what actually shipped. Expands both releases' changelog entries to list every underlying feature/fix, sourced from each batch PR's own itemized description (which already documented them in detail — the changelog just never surfaced it). No functional/behavioral change, `CHANGELOG.md` only, plus one unrelated one-line `.gitignore` fix for a local E2E test-server pid file that kept showing up as untracked. ## Test plan - [x] Docs-only change, no code touched. - [x] Cross-checked every expanded bullet against its source PR's own description (`gh pr view <n>`) rather than reconstructing from raw commit diffs. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This was referenced Sep 8, 2026
Closed
Closed
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Integration branch bundling 8 specs implemented this session (each on its own
feat/branch, audited for completeness, then--no-ffmerged here). 74 commits ahead ofmain.What's included
Frontend / brand (low-risk):
logo.svg(verified byte-match) and propagated to bothpublic/+ embedded dirs.Status model (foundational):
Warning(live, value 8) +Degraded(aggregated rollup, value 7) across all three status enums; widenedresults.statusCHECK (both dialects, also fixing the missing6/error); Warning counts as up for availability; aggregation promotes a non-failing window containing a Warning to Degraded with aSeverity()tie-break; Warning is incident-neutral (never opens/resolves an incident); one sharedstatusStyle()util across dash0 + status0.Checks (build on the status model):
warningDays/criticalDays(legacythresholdDaysaliased), expiry decided by the whole-chain minimum, chain-report output + UI. Warning tier → amber (no page); critical → Down (pages).restartLoopMinRestarts/restartLoopWindow); a running-but-crash-looping container →Warning(doesn't page); not-running/unhealthy still → Down.Larger features:
/.well-known/*) + RFC 8707 audience binding,/authorize+consent+/tokenwith mandatory PKCE S256, single-use codes, rotating refresh, RFC 7591 DCR with loopback exception. PAT-bearer back-compat preserved.POST /orgs/:org/checks/apply(+sp apply) reconciling the existing export format: managed-label scope, dry-run/diff, delete-by-absence gated byprune+ managed-label + deletion cap,${env:}/${param:}secret references resolved server-side.sp checks export/importadded.Reviewer notes / caveats
jwks_uriserves an empty keyset because tokens are signed with a symmetric HS256 key (publishing it would leak the secret); an asymmetric keyset is the documented follow-on. Four design forks (SaaS multi-tenant issuers, asymmetric JWKS, first real-client validation, per-org issuer) were left to revisit during that review./checks/exportand/checks/importendpoints to admin-only (they were auth-only). A non-admin who scripted them will now get 403 — worth a release note.Warningnotification fan-out, and wiring the graded-expiry helper intocheckdomain.results.statusCHECK in001(both dialects); MCP OAuth adds002_mcp_oauth(both dialects); config-as-code adds no migration.embedded-postgresintermittently fails to start (dyld code-signing) — pre-existing and unrelated; the suites that matter ran green via testcontainers/SQLite.🤖 Generated with Claude Code