Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
430026e
feat(backup): make PostgreSQL point-in-time recovery executable
vishr Aug 19, 2026
9db9f2c
refactor(backup): run PostgreSQL protection on wal-g, not pgBackRest
vishr Aug 19, 2026
5f62361
fix(backup): install protection credentials, and stop minio claiming …
vishr Aug 19, 2026
c43dc42
fix(doctor): stop reporting protected services as unprotected
vishr Aug 19, 2026
23f7edd
feat(backup): recover to a point in time, and prove it without touchi…
vishr Aug 19, 2026
0c5aeae
feat(backup): install the schedules the policy declares
vishr Aug 19, 2026
e29d570
feat(backup): disable protection without touching the backups
vishr Aug 19, 2026
a2f5d66
fix(backup): stop a deploy from deleting every scheduled backup
vishr Aug 19, 2026
36b096c
fix(backup): keep the recovery window the policy promises
vishr Aug 19, 2026
13f7c10
spec!: rename the backup surface and group the checks
vishr Aug 19, 2026
3f67b9a
docs: say that backups exist, and write the guide for them
vishr Aug 19, 2026
972419c
refactor(backup): delete the agent-on-target scheduling that systemd …
vishr Aug 20, 2026
22d0995
refactor(backup): delete the rest of the unreachable protection model
vishr Aug 20, 2026
8df6732
spec!: abbreviate the maximum_/minimum_ prefixes
vishr Aug 20, 2026
e8362c4
chore: remove the symbols the protection deletions orphaned
vishr Aug 20, 2026
cb9483e
fix(backup): address the code review on #80
vishr Aug 20, 2026
6519693
fix(backup): address the second code review on #80
vishr Aug 20, 2026
f184b1d
fix(backup): do not re-pull an image the host already has pinned
vishr Aug 20, 2026
82585e7
refactor: carry the schema rename into code, filenames, and docs
vishr Aug 20, 2026
6f6c11e
fix(backup): three defects a live PostgreSQL recovery found
vishr Aug 20, 2026
5b414a3
refactor: delete the parts of onebox that described work instead of d…
vishr Aug 20, 2026
6e72c2f
fix: wire the disable-pending refusal, and delete what the cut orphaned
vishr Aug 20, 2026
38b8c66
perf(registry): stop asking the registry for what the host already has
vishr Aug 20, 2026
17e311d
fix(compose): the declared pull policy has to reach Compose, not just…
Aug 20, 2026
a06ce67
fix(backup): make disable-pending cover the work it names
vishr Aug 20, 2026
ad7e8d5
fix(backup): recover to the point that was asked for, not to the newe…
vishr Aug 20, 2026
00f0c1e
fix(backup): the verify check reported green over a broken WAL chain
vishr Aug 20, 2026
2a2087a
fix(backup): refuse a policy no driver can establish, and report the …
vishr Aug 20, 2026
666e405
fix(backup): the scheduled archive check could not fail either
vishr Aug 20, 2026
b98f627
refactor(journal): delete the backup journal model nothing writes
vishr Aug 20, 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
51 changes: 24 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,21 +70,17 @@ clickhouse, nats. Anything else is refused rather than guessed at, because
inventing an image from a name produces a container that starts and stores
nothing durable.

Onebox does **not** take backups, and `ob doctor` says so for every workload and
service holding durable data. It also refuses a major version change a driver
cannot perform in place, rather than replacing the container and leaving the
data intact and unreachable.

The schema can already declare desired log, metric, and alert capabilities.
The local engine does **not** manage those continuous services yet, and reports
them as declared rather than managed. The planned
dashboard/control plane will add authenticated team approvals, continuous
evidence, shared policy, and recovery assurance without becoming a generic
Docker UI.

Versioned driver contracts and continuous observability management are not
shipped. Plan/status drift observation and plan-bound migration backup reports
are shipped; Onebox still does not create or store the backup itself.
Onebox takes PostgreSQL backups: continuous WAL archiving to a repository you
own, point-in-time restore, and a drill that proves recovery without touching
the live service. Every other driver **refuses** a backup policy rather than
accepting one it cannot honour, and `ob doctor` says which is which for every
workload and service holding durable data. It also refuses a major version
change a driver cannot perform in place, rather than replacing the container
and leaving the data intact and unreachable.

The planned dashboard/control plane will add authenticated team approvals,
continuous evidence, shared policy, and recovery assurance without becoming a
generic Docker UI.

## Start using it

Expand Down Expand Up @@ -172,8 +168,8 @@ Executable plans use
`onebox.run/executable-deploy-plan/v1alpha2` and include the planner's version,
source revision, build time, dirty state, and supported schemas. Schema-less
and unsupported plans are rejected. Environment policy can set
`minimum_onebox_version` using the exact CalVer release form and can set
`minimum_plan_schema`; `ob doctor` reports whether the runner selected by
`min_onebox_version` using the exact CalVer release form and can set
`min_plan_schema`; `ob doctor` reports whether the runner selected by
`PATH` is compatible. When a minimum version is configured, commit-derived and
dirty checkout builds fail closed because they are not released runners.

Expand Down Expand Up @@ -289,16 +285,17 @@ headers, and scalar JSON values. Migration verification can bind the expected
provider and applied revisions to the captured job-result evidence:

```yaml
verifications:
- url: https://app.example.com/healthz
status_codes: [200]
required_headers:
X-App-Ready: "yes"
json_assertions:
- path: service.ready
equals: true
- migration_revisions:
job: migrate
checks:
url:
- url: https://app.example.com/healthz
status_codes: [200]
required_headers:
X-App-Ready: "yes"
json_assertions:
- path: service.ready
equals: true
migrations:
- job: migrate
provider: atlas
applied_revisions: ["202607130001"]
```
Expand Down
35 changes: 12 additions & 23 deletions cmd/ob-docgen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,8 +293,8 @@ var blocks = []block{
{Key: "deployment", Title: "deployment", Order: 50, Status: statusShipped,
Summary: "Release ordering, how many releases are retained for rollback, and the migration policy.",
ReadWhen: []string{"Changing release order, retention or migration gating"}},
{Key: "verifications", Title: "verifications", Order: 60, Status: statusShipped,
Summary: "What must be true before a release becomes current: external URLs, in-workload checks, or migration revision evidence.",
{Key: "checks", Title: "checks", Order: 60, Status: statusShipped,
Summary: "What must be true before a release becomes current, grouped by kind: external URLs, in-workload HTTP or exec probes, or migration revision evidence.",
ReadWhen: []string{"Gating release activation on a health endpoint or a smoke test"}},
{Key: "proxy", Title: "proxy", Order: 70, Status: statusShipped,
Summary: "Who owns the ingress proxy, which image runs it, and how TLS is resolved.",
Expand All @@ -308,14 +308,11 @@ var blocks = []block{
{Key: "notifications", Title: "notifications", Order: 100, Status: statusShipped,
Summary: "Named webhooks that receive selected operation outcomes.",
ReadWhen: []string{"Sending deploy outcomes to Slack, Discord or an incident tool"}},
{Key: "observability", Title: "observability", Order: 110, Status: statusIntentOnly,
Summary: "Declared logging, metric and alerting intent. Validated and planned, but the local engine runs nothing continuous for it.",
ReadWhen: []string{"Recording observability intent that another system will act on"}},
{Key: "backup_targets", Title: "backup_targets", Order: 200, Status: statusSchemaOnly,
Summary: "User-owned off-host S3-compatible repositories available to service protection policies. Accepted by the loader; not yet executable.",
ReadWhen: []string{"Evaluating the proposed protection layer", "Understanding why Onebox refuses a backup target that shares the protected host"}},
{Key: "backup_targets", Title: "backup_targets", Order: 200, Status: statusShipped,
Summary: "User-owned off-host S3-compatible repositories a protected service writes its backups to. Executable for the postgres driver; every other driver refuses a policy rather than accepting one it cannot honour.",
ReadWhen: []string{"Declaring where a database's backups go", "Understanding why Onebox refuses a backup target that shares the protected host"}},
{Key: "external_services", Title: "external_services", Order: 210, Status: statusSchemaOnly,
Summary: "Typed dependencies operated outside Onebox, whose lifecycle and protection stay external. Accepted by the loader; not yet executable.",
Summary: "Typed dependencies operated outside Onebox, whose lifecycle and backups stay external. Accepted by the loader; not yet executable.",
ReadWhen: []string{"Modelling an RDS, Neon, Supabase or Upstash dependency"}},
}

Expand Down Expand Up @@ -888,32 +885,24 @@ func renderErrorPage() string {

fmt.Fprintln(&buf, "## Lifecycle failure codes")
fmt.Fprintln(&buf)
fmt.Fprintln(&buf, ":::caution[Belongs to the proposed protection layer]")
fmt.Fprintln(&buf, "These codes are defined and drift-tested in the binary, but the operations that")
fmt.Fprintln(&buf, "raise most of them are not yet executable. A row marked **reserved** is one no")
fmt.Fprintln(&buf, "path raises today: the code is fixed so it stays stable when the capability")
fmt.Fprintln(&buf, "lands, but you cannot cause it. The set is computed from the source, not")
fmt.Fprintln(&buf, "maintained by hand.")
fmt.Fprintln(&buf, ":::")
fmt.Fprintln(&buf, "Every code here is raised by a path in the shipped binary, checked against the")
fmt.Fprintln(&buf, "source by a test in both directions. The table is computed, not maintained by")
fmt.Fprintln(&buf, "hand.")
fmt.Fprintln(&buf)
fmt.Fprintln(&buf, "The failure contract shared by plans, event streams, terminal results, status and")
fmt.Fprintln(&buf, "doctor. Each carries a stable code and one safe command in its semantic role; diagnostic")
fmt.Fprintln(&buf, "detail stays in restricted local evidence, never in the public record.")
fmt.Fprintln(&buf)
fmt.Fprintln(&buf, "| Code | Reachable | Means | Guidance role | Command |")
fmt.Fprintln(&buf, "| --- | --- | --- | --- | --- |")
fmt.Fprintln(&buf, "| Code | Means | Guidance role | Command |")
fmt.Fprintln(&buf, "| --- | --- | --- | --- |")
for _, code := range onebox.LifecycleFailureCodes() {
// A code that will not resolve is a defect in the contract, not a row to
// drop: a shorter table is one nobody can tell is incomplete.
failure, err := onebox.NewLifecycleFailure(code)
if err != nil {
panic(fmt.Sprintf("lifecycle code %q does not resolve: %v", code, err))
}
reach := "yes"
if onebox.LifecycleFailureReserved(code) {
reach = "reserved"
}
fmt.Fprintf(&buf, "| `%s` | %s | %s | %s | `%s` |\n", code, reach, escapeCell(failure.Message), failure.GuidanceRole(), failure.GuidanceCommand())
fmt.Fprintf(&buf, "| `%s` | %s | %s | `%s` |\n", code, escapeCell(failure.Message), failure.GuidanceRole(), failure.GuidanceCommand())
}

return buf.String()
Expand Down
81 changes: 0 additions & 81 deletions cmd/ob-scheduled-runner/main.go

This file was deleted.

47 changes: 0 additions & 47 deletions cmd/ob-scheduled-runner/main_test.go

This file was deleted.

Loading