diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 87ebfbf..1296712 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,6 +46,29 @@ jobs: - name: Lint run: make lint + # dbpantry and mesobia ship binaries for macOS and Windows, so cloudkit must + # build and pass there too. Pull requests test on Linux only; the other OSes + # run weekly and by hand. + cross-os: + if: github.event_name != 'pull_request' + runs-on: ${{ matrix.os }} + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + os: [macos-latest, windows-latest] + steps: + - uses: actions/checkout@v7 + with: + persist-credentials: false + - uses: actions/setup-go@v7 + with: + go-version-file: src/go.mod + cache: false + - name: Gate + shell: bash + run: make ci + gitleaks: if: github.event_name != 'pull_request' || !github.event.pull_request.draft runs-on: ubuntu-latest diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0b1c53c..5fa4481 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,6 +11,12 @@ name: Release # # src/internal/policy's TestReleaseRunsOnlyOnAConfirmedDispatch fails if this # file gains an automatic trigger or loses the confirmation. +# +# GitHub registers a workflow that has no push or pull_request trigger only +# when a push to the default branch changes the file; until then a dispatch +# answers 404 "workflow not found on the default branch". The repository's +# first push did not register it, so this comment's own merge is what did. +# Check before tagging: gh workflow list --repo simtabi/cloudkit shows Release. on: workflow_dispatch: inputs: diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ea4436..86f7945 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,3 +19,10 @@ All notable changes to this project are documented here. The format follows workflow triggers; action pinning. - CI on pull requests, by dispatch and weekly; a release workflow that runs only on a confirmed dispatch against a `v` tag. +- A weekly and on-demand CI leg on macOS and Windows; pull requests still test on Linux only. + +### Changed + +- The architecture guide states the scope split: cloudkit finds and connects to managed databases + but never administers them, and REST descriptors (planned) support writes behind signing or + explicit enablement, plans and the contract suite. diff --git a/docs/architecture.md b/docs/architecture.md index 0d312de..1395d6a 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -12,6 +12,13 @@ provisioning hosts, and mesobia for its provider drivers. | The generic path: SSH to any host, and a cloud-init renderer | What is installed on the host | | One error model, one retry policy, one redaction rule | CLI, API, UI and configuration loading | | A contract test kit every adapter passes | | +| Managed databases: finding them and returning connection details | All database administration, managed engines included | +| REST descriptors: providers without a compiled adapter, reads and writes | | + +cloudkit has no database logic. It finds managed database instances (RDS, Cloud SQL, DigitalOcean +databases and the like) and says how to reach them, including a provider-issued short-lived connect +credential where one exists; creating users, databases or pools is the consumer's work, done through +its own engine adapters. ## Rules @@ -46,6 +53,17 @@ Each consumer has its own command tree and configuration loader. A library that config package would force them on both, so cloudkit takes plain structs and an injected `*slog.Logger`, and each consumer maps its own configuration onto them. +## Why descriptors may write + +Most providers in the long tail have an HTTP API and no maintained Go SDK. A descriptor maps that +API onto the same capability interfaces as a compiled adapter, reads and writes alike, so a new +provider needs no release. Writes keep every guarantee a compiled adapter has: each one is planned +against the live state, a destroy must declare what it loses and needs the name typed back, paths +outside the declared API hosts are rejected, a descriptor never holds a credential, and write +operations load only from a descriptor that is signed by a trusted key or enabled by the consumer +for that provider and account. Every descriptor passes the same contract suite as a compiled adapter +before it loads. + ## Layout | Path | Holds | @@ -54,8 +72,8 @@ config package would force them on both, so cloudkit takes plain structs and an | `src/internal/policy/` | repository-wide tests: forbidden symbols, workflow guards | Planned packages are added when they have code: `providers/` (wave 1: Hetzner, DigitalOcean, -Linode, Vultr; plus `generic` for any SSH host), `ssh/`, `cloudinit/`, `transport/` and -`cloudkittest/`. +Linode, Vultr; plus `generic` for any SSH host), `ssh/`, `cloudinit/`, `transport/`, `descriptor/` +and `cloudkittest/`. --- diff --git a/docs/getting-started.md b/docs/getting-started.md index 34ecec9..45486b0 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -78,8 +78,8 @@ URL with them before logging it. ## What comes next The registry, capability probes, plans with drift refusal, the contract test kit, the SSH path, the -cloud-init renderer and the first provider adapters (Hetzner, DigitalOcean, Linode, Vultr) are -planned; see [Architecture](architecture.md). +cloud-init renderer, the first provider adapters (Hetzner, DigitalOcean, Linode, Vultr), managed +database discovery and REST descriptors are planned; see [Architecture](architecture.md). --- diff --git a/docs/release.md b/docs/release.md index 74c3822..00e5f23 100644 --- a/docs/release.md +++ b/docs/release.md @@ -5,6 +5,9 @@ and a GitHub release whose body is the version's CHANGELOG section. There are no ## Steps +0. Check the workflow is registered: `gh workflow list --repo simtabi/cloudkit` lists `Release`. + GitHub registers a dispatch-only workflow only when a push to `main` changes it, so a fresh copy + of the repository answers 404 until then. 1. Move the `[Unreleased]` entries in `CHANGELOG.md` under a dated `## [X.Y.Z] - YYYY-MM-DD` heading, through a pull request. 2. After it merges, tag the merge commit and push the tag: