Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 17 additions & 0 deletions .config/nextest.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Nextest configuration for pinax.
# See: https://nexte.st/book/configuration.html

[profile.default]
slow-timeout = { period = "60s", terminate-after = 5 }

[profile.ci]
# WHY no retries in the profile the required gate runs: a retry makes the
# check non-deterministic in the PASS direction — a test that fails once and
# passes on retry reports green, so the Gate-Passed trailer attests a result
# the same commit may not reproduce, and the flake itself is never seen.
# Flakes are defects to fix, not results to average away.
retries = 0
slow-timeout = { period = "60s", terminate-after = 2 }

[profile.ci.junit]
path = "target/nextest/ci/junit.xml"
87 changes: 87 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# WHY: gate-attestation.yml here is still the org-default trailer-only
# reusable (no full-build fallback) -- unlike sphragis and heurema, which
# moved to forkwright/.github's hybrid-gate.yml (kanon#2522) and run this
# same fmt/check/clippy/nextest matrix as the trailer-less fallback build.
# Until pinax makes that same move, this workflow is the only build signal
# it runs on every PR; it is informational (not a required check) and does
# not substitute for the Gate-Passed trailer branch protection requires.
name: CI

on:
pull_request:
branches: [main]
push:
branches: [main]
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

env:
CARGO_TERM_COLOR: always

jobs:
fmt:
name: cargo fmt
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
components: rustfmt
- name: cargo fmt check
run: cargo fmt --all -- --check

check:
name: cargo check
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
- name: cargo check workspace
run: cargo check --workspace --all-targets

clippy:
name: cargo clippy
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
components: clippy
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
- name: clippy workspace
run: cargo clippy --workspace --all-targets -- -D warnings

test:
name: cargo test
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
- uses: taiki-e/install-action@41049aa56687c35e0afa74eed4f09cec4f9afabf # v2.85.2
with:
tool: nextest
- name: cargo nextest run workspace
run: cargo nextest run --workspace
- name: cargo test doc
# NOTE: nextest does not execute doctests.
run: cargo test --workspace --doc
7 changes: 6 additions & 1 deletion .github/workflows/gate-attestation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,9 @@ concurrency:

jobs:
call:
uses: forkwright/.github/.github/workflows/gate-attestation.yml@main
# WHY pinned to a commit SHA, not @main: a mutable branch ref lets the
# remote workflow's behavior change under an already-merged pinax
# commit. Refresh via:
# gh api repos/forkwright/.github/commits/main --jq '.sha'
# and review the diff at forkwright/.github before bumping.
uses: forkwright/.github/.github/workflows/gate-attestation.yml@df92942bcc41cc7ffd0339b75b2f01e52269d0ef # main
7 changes: 6 additions & 1 deletion .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,9 @@ permissions:

jobs:
call:
uses: forkwright/.github/.github/workflows/release-please.yml@main
# WHY pinned to a commit SHA, not @main: a mutable branch ref lets the
# remote workflow's behavior change under an already-merged pinax
# commit. Refresh via:
# gh api repos/forkwright/.github/commits/main --jq '.sha'
# and review the diff at forkwright/.github before bumping.
uses: forkwright/.github/.github/workflows/release-please.yml@df92942bcc41cc7ffd0339b75b2f01e52269d0ef # main
86 changes: 86 additions & 0 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# WHY: Block merges on known vulnerabilities and license/source/ban
# violations. Runs `cargo audit` (RustSec DB), `cargo deny check`
# (licenses, sources, bans, advisories), and OSV-Scanner on every PR and
# daily against main so newly-published CVEs against existing deps are caught
# even when no PR is open.
name: Security

on:
pull_request:
branches: [main]
push:
branches: [main]
schedule:
# NOTE: Daily at 05:23 CST (11:23 UTC). Off-peak minute per global
# rule about avoiding :00/:30 cron schedules.
- cron: "23 11 * * *"
workflow_dispatch:

# PROJECT: explicit top-level default deny; job-level permissions grant only what's needed
permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

env:
CARGO_TERM_COLOR: always

jobs:
cargo-deny:
# WHY: checks licenses, banned crates, source registries, and the
# RustSec advisory DB using deny.toml ignore list. Any finding fails
# the job -- suppressions require a deny.toml entry with a WHY comment,
# not silent --ignore flags.
name: cargo deny
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false # PROJECT: security hardening -- never expose token to steps
- uses: EmbarkStudios/cargo-deny-action@bb137d7af7e4fb67e5f82a49c4fce4fad40782fe # v2.0.20
with:
# WHY: run every check explicitly so a schema regression in one
# section can't silently disable the others. cargo-deny expects
# the check subcommand followed by space-separated check names;
# `arguments:` passes post-subcommand flags only.
command: check advisories licenses bans sources
arguments: --all-features

cargo-audit:
# WHY: cargo-deny advisories check overlaps but uses a different code
# path; running cargo-audit independently protects against bugs or
# config drift disabling one of the two.
name: cargo audit
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable
# WHY: install a prebuilt cargo-audit binary rather than source-building
# with this crate's pinned toolchain -- that decouples the scanner's
# MSRV (cargo-audit 0.22.2 requires Rust >=1.88) from the audited
# crate's MSRV. The exact scanner version is pinned and deliberately
# reviewed, never floated.
- uses: taiki-e/install-action@43aecc8d72668fbcfe75c31400bc4f890f1c5853 # v2.83.2
with:
tool: cargo-audit@0.22.2
- name: cargo audit
# WHY: -D unmaintained,unsound,yanked escalates those categories
# to errors (default is warning only). Suppressions go through
# deny.toml advisories.ignore entries -- no silent --ignore flags here.
run: cargo audit --deny unmaintained --deny unsound --deny yanked

osv-scanner:
name: osv scanner
uses: google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@9a498708959aeaef5ef730655706c5a1df1edbc2
permissions:
actions: read
contents: read
security-events: write
with:
scan-args: '--config=osv-scanner.toml --lockfile=Cargo.lock'
48 changes: 29 additions & 19 deletions .kanon-ci.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,9 @@
# forge-only: false
# spdx: LicenseRef-PolyForm-Shield-1.0.0

# Pinax CI pipeline.
#
# Pinax is docs-only today (design phase) - no Cargo.toml, no
# crates, nothing for the default Rust gate to exercise. The docs-phase
# gate keeps CI honest with real checks that do not require a Rust
# workspace: the canonical whole-repository lint, plus the README
# writing check on top of it.
#
# The workspace lands at Phase 01 (pager / buffer pool / B-tree).
# When code lands, replace `pipeline.stages` with the full Rust gate:
#
# stages = ["cargo fmt", "cargo check", "cargo clippy", "cargo nextest", "kanon lint"]
# NOTE: Pinax CI pipeline -- full Rust gate (fmt / check / clippy / nextest)
# over the four-crate workspace, plus the repo-wide and README-prose kanon
# lint passes.

# WHY(#1) `kanon lint .` and not the two scoped commands it replaces: the
# pipeline previously ran `kanon lint --workflow .kanon-ci.toml` and
Expand All @@ -23,8 +14,29 @@
# least likely to have drifted and excluded the ones that had. The
# whole-repo lint subsumes the workflow check; the README writing check stays
# because `--writing` applies prose rules the default pass does not.
#
# WHY --jobs 8 / --build-jobs 8 --test-threads 8: kanon-ci concurrency caps
# (basanos CI.md) -- the fleet budget for one CI run is ~25GB RSS; uncapped
# cargo/nextest use host CPU count and can exceed it under parallel rustc
# plus test workers.
[pipeline]
stages = ["repo-lint", "readme-lint"]
stages = ["cargo fmt", "cargo check", "cargo clippy", "cargo nextest", "repo-lint", "readme-lint"]

[stages."cargo fmt"]
cmd = "cargo fmt --all -- --check"
timeout_secs = 300

[stages."cargo check"]
cmd = "cargo check --workspace --all-targets --jobs 8"
timeout_secs = 600

[stages."cargo clippy"]
cmd = "cargo clippy --workspace --all-targets --jobs 8 -- -D warnings"
timeout_secs = 600

[stages."cargo nextest"]
cmd = "cargo nextest run --workspace --build-jobs 8 --test-threads 8"
timeout_secs = 600

[stages.repo-lint]
cmd = "kanon lint ."
Expand All @@ -34,9 +46,7 @@ timeout_secs = 120
cmd = "kanon lint --writing README.md"
timeout_secs = 30

# WHY disabled: the independent verifier's default build probe
# (`cargo check --all-features --tests`) fails structurally against a
# repo with no Cargo workspace and reports a false divergence.
# Re-enable when the pipeline grows real Rust stages to reproduce.
[verifier]
enabled = false
# NOTE: [verifier] omitted -- the workspace now exists, so the independent
# verifier's default build probe reproduces cleanly; the prior explicit
# `enabled = false` (docs-only repo, no Cargo workspace to probe) no longer
# applies. Absent section defaults to enabled per basanos VerifierConfig.
50 changes: 50 additions & 0 deletions .kanon-lint-ignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Rules to skip for specific paths
# Format: RULE/name:path/glob

# =============================================================================
# crates/lexis/ — false positives, not real defects
# =============================================================================

# WHY: lexis's lib.rs is a module-declaration + public re-export file with no
# behavior of its own; its 41 tests live in the schema.rs and types.rs
# submodules (#[cfg(test)] mod tests, plus proptest properties). The
# TESTING/no-tests heuristic only inspects lib.rs itself and a sibling
# tests/ directory, so it cannot see submodule test coverage. Same
# false-positive shape and same fix as the existing
# TESTING/no-tests:crates/mnemosyne/src/lib.rs entry in kanon's own
# .kanon-lint-ignore.
TESTING/no-tests:crates/lexis/src/lib.rs

# WHY(forkwright/kanon#2975): STORAGE/no-migration-checksum's has_ddl check
# is a bare substring match for CREATE/ALTER/DROP TABLE with no requirement
# that the keyword be co-located with an execution call or migration
# runner — unlike has_migration_runner, which requires an actual
# function/module identifier (kanon#1040 B7 narrowed that path specifically
# to avoid firing on bare-word mentions in doc-comment prose, but has_ddl
# never received the same treatment). Both lexis files here are pure
# type-vocabulary code (#![forbid(unsafe_code)], no DB connection, no SQL
# execution) whose module doc comments explicitly name "CREATE TABLE" as
# one of the future statement types the crate does NOT implement. Evidence
# posted to kanon#2975; drop this entry once that rule fix lands.
STORAGE/no-migration-checksum:crates/lexis/src/ast.rs
STORAGE/no-migration-checksum:crates/lexis/src/lib.rs

# =============================================================================
# crates/{hypomnema,phylaxis,pinax}/ — genuinely empty scaffolds
# =============================================================================

# WHY: these three crates are empty by design at this phase — lib.rs is
# module-doc-comment-only, zero functions, zero types, zero logic (see each
# crate's [package.metadata.kanon] maturity = "scaffold" in Cargo.toml). A
# #[cfg(test)] module here would have no real behavior to assert against;
# writing one anyway would itself be a tautological/vacuous test (the
# TESTING/tautological-test class this same lint run flags elsewhere), which
# is worse than an honest, exit-criteria-bound suppression. Each crate's own
# Cargo.toml exit-criteria field names the concrete Phase that ends this:
# hypomnema Phase 02 (WAL + virtual-WAL trait + causal changelog), phylaxis
# Phase 03/06 (MVCC + encryption), pinax Phase 01 (pager + buffer pool +
# B-tree) — see kanon/projects/pinax/ROADMAP.md. Drop each entry the moment
# its crate gets real behavior and a real test.
TESTING/no-tests:crates/hypomnema/src/lib.rs
TESTING/no-tests:crates/phylaxis/src/lib.rs
TESTING/no-tests:crates/pinax/src/lib.rs
37 changes: 37 additions & 0 deletions CRATE-INDEX.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Layers rank the workspace from foundation upward. A crate may depend on
# its own layer or any layer below it; ARCHITECTURE/crate-index-conformance
# rejects an edge that points up. Mirrors Decision 14's locked dependency
# graph exactly: lexis -> hypomnema -> phylaxis -> pinax.
layer_order = ["vocabulary", "record", "guard", "facade"]

[crates.lexis]
layer = "vocabulary"
purpose = "Language of data: strict six-type value system, schema DDL, and query-expression AST vocabulary. Leaf crate — no fleet dependencies (Decision 5, Decision 14)."
path = "crates/lexis"
depends_on = []
used_by = ["hypomnema", "phylaxis", "pinax"]
dev_depends_on = []

[crates.hypomnema]
layer = "record"
purpose = "Written record: WAL, virtual-WAL trait, and cr-sqlite-shaped causal changelog feeding antigraphos (Decision 3, Decision 8, Decision 14)."
path = "crates/hypomnema"
depends_on = ["lexis"]
used_by = ["phylaxis", "pinax"]
dev_depends_on = []

[crates.phylaxis]
layer = "guard"
purpose = "Guarding: MVCC snapshot isolation, per-page AEAD encryption, and the heurēma index adapter (Decision 4, Decision 9, Decision 14)."
path = "crates/phylaxis"
depends_on = ["lexis", "hypomnema"]
used_by = ["pinax"]
dev_depends_on = []

[crates.pinax]
layer = "facade"
purpose = "Facade: pager, buffer pool, B-tree, page format, SQL surface (parser/planner/executor), async API, migration runner, CLI (Decision 1, Decision 2, Decision 6, Decision 7, Decision 10, Decision 12, Decision 14)."
path = "crates/pinax"
depends_on = ["lexis", "hypomnema", "phylaxis"]
used_by = []
dev_depends_on = []
Loading