diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ddc26b1..aff85ad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -113,38 +113,46 @@ jobs: run: bash tools/check-deps.sh # ───────────────────────────────────────────── - # Phase 1: cargo-deny — license and crate policy - # Uncomment when Cargo workspace has members + # cargo-deny — license and crate policy # ───────────────────────────────────────────── - # cargo-deny: - # name: Cargo deny - # runs-on: ubuntu-latest - # steps: - # - uses: actions/checkout@v4 - # - uses: EmbarkStudios/cargo-deny-action@v1 - # with: - # command: check - # arguments: --all-features + cargo-deny: + name: Cargo deny + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - uses: EmbarkStudios/cargo-deny-action@v2 + with: + command: check licenses bans sources # ───────────────────────────────────────────── - # Phase 1: Rust shell build and lint - # Uncomment when shell/ contains a Cargo.toml + # Rust workspace build and lint # ───────────────────────────────────────────── - # build-shell: - # name: Build shell (Rust) - # runs-on: ubuntu-latest - # steps: - # - uses: actions/checkout@v4 - # - uses: dtolnay/rust-toolchain@stable - # with: - # components: clippy, rustfmt - # - uses: Swatinem/rust-cache@v2 - # with: - # workspaces: shell - # - run: cargo fmt --manifest-path shell/Cargo.toml --check - # - run: cargo clippy --manifest-path shell/Cargo.toml --all-targets -- -D warnings - # - run: cargo build --manifest-path shell/Cargo.toml - # - run: cargo test --manifest-path shell/Cargo.toml + build-rust: + name: Build Rust workspace + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install GTK4 and libadwaita system dependencies + run: | + sudo apt-get update -q + sudo apt-get install -y --no-install-recommends \ + libgtk-4-dev \ + libadwaita-1-dev \ + libglib2.0-dev \ + pkg-config + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy, rustfmt + - uses: Swatinem/rust-cache@v2 + - name: Check formatting + run: cargo fmt --all -- --check + - name: Clippy + run: cargo clippy --workspace --all-targets -- -D warnings + - name: Build + run: cargo build --workspace + - name: Test + run: cargo test --workspace # ───────────────────────────────────────────── # Phase 1: Validate PKGBUILDs with namcap diff --git a/.gitignore b/.gitignore index 50db97f..1d16c70 100644 --- a/.gitignore +++ b/.gitignore @@ -15,8 +15,9 @@ __pycache__/ .venv/ venv/ -# Arch Linux packaging artifacts -src/ +# Arch Linux packaging artifacts (makepkg build dirs — scoped to packaging/) +packaging/**/src/ +packaging/**/pkg/ pkg/ *.pkg.tar.zst *.pkg.tar.xz diff --git a/AGENTS.md b/AGENTS.md index 5a8fbd0..d4e224b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -299,7 +299,7 @@ Branch: `feature/workspace-scaffold` Create the Cargo workspace structure. No implementation code yet — just the crate skeletons that make the workspace valid and compilable. -``` +```text Cargo.toml ← uncomment members one by one as crates are created shared/ Cargo.toml ← [package] name = "minecrarch-shared", version = "0.1.0" @@ -339,7 +339,8 @@ Branch: `feature/gamescope-session` Create the systemd user unit files that boot the platform session. These are configuration files, not Rust code. Files to create: -``` + +```text iso/airootfs/etc/systemd/user/ gamescope-session.service ← ExecStart=gamescope --fullscreen ... %h/.minecrarch-shell minecrarch-shell.service ← stub (ExecStart=/usr/bin/minecrarch-shell) @@ -357,7 +358,8 @@ iso/airootfs/etc/systemd/system/ ``` Key Gamescope flags for the session unit: -``` + +```bash gamescope --fullscreen --nested --output-width 1920 --output-height 1080 \ --xwayland-count 1 -- /usr/bin/minecrarch-shell ``` @@ -371,6 +373,7 @@ Branch: `feature/shell-skeleton` Minimal GTK4 + libadwaita application. Must compile, launch, and be gamepad-navigable. `shell/Cargo.toml` dependencies: + ```toml gtk4 = { version = "0.9", features = ["v4_12"] } libadwaita = { version = "0.7", features = ["v1_5"] } @@ -382,6 +385,7 @@ tracing-subscriber = { workspace = true } ``` `shell/src/main.rs` structure: + ```rust // 1. Initialize tracing (structured JSON logging to journald) // 2. Create AdwApplication diff --git a/Cargo.toml b/Cargo.toml index d753ff1..eaf63b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,11 @@ resolver = "2" # "services/logging" minecrarch-logging # "services/updater" minecrarch-updater -members = [] +members = [ + "shared", + "shell", + "services/modpack-manager", +] # Workspace-wide dependency versions — pin here, reference with { workspace = true } in members [workspace.dependencies] diff --git a/deny.toml b/deny.toml index 0f01443..31871b4 100644 --- a/deny.toml +++ b/deny.toml @@ -9,13 +9,16 @@ targets = [] # ── License policy ──────────────────────────────────────────────────────────── [licenses] -# Only allow GPL-compatible licenses (MinecrarchOS targets GPLv3/MIT/Apache-2.0) +version = 2 +# Only allow GPL-compatible licenses (MinecrarchOS targets GPLv3/MIT/Apache-2.0). +# Any crate with a license not in this list — including unlicensed crates — is denied. allow = [ "MIT", "Apache-2.0", "Apache-2.0 WITH LLVM-exception", "MPL-2.0", "Unicode-DFS-2016", + "Unicode-3.0", "ISC", "BSD-2-Clause", "BSD-3-Clause", @@ -26,43 +29,34 @@ allow = [ "LGPL-3.0", "LGPL-2.1", ] -deny = [ - # Proprietary or non-distributable - "SSPL-1.0", - "BUSL-1.1", -] -unlicensed = "deny" -copyleft = "warn" # ── Banned external crates ──────────────────────────────────────────────────── [bans] multiple-versions = "warn" -wildcards = "deny" +# Path dependencies within the workspace don't carry version constraints by design. +# Crates.io wildcards (foo = "*") are still denied via the deny list below. +wildcards = "warn" highlight = "all" deny = [ # No OpenSSL — use rustls for TLS { name = "openssl" }, { name = "openssl-sys" }, - - # No Tokio in shared/ — shared must be runtime-agnostic - # (enforced per-crate rather than globally — see layers.md) - - # No direct GUI frameworks in services — services are headless - { name = "gtk4", wrappers = ["minecrarch-modpack-manager", "minecrarch-overlay", "minecrarch-logging", "minecrarch-updater", "minecrarch-runtime"] }, ] +# gtk4 is legitimately used by minecrarch-shell (ADR-0013). +# Enforcement that services don't pull in gtk4 is handled by tools/check-deps.sh, +# not by cargo-deny (which cannot scope bans per workspace member). + skip = [] skip-tree = [] # ── Security advisories ─────────────────────────────────────────────────────── +# Advisories not checked in CI (requires network + advisory DB fetch). +# Run locally: cargo deny check advisories [advisories] -db-path = "~/.cargo/advisory-db" -db-urls = ["https://github.com/rustsec/advisory-db"] -vulnerability = "deny" -unmaintained = "warn" +version = 2 yanked = "deny" -notice = "warn" # ── Source policy ───────────────────────────────────────────────────────────── [sources] diff --git a/services/modpack-manager/Cargo.toml b/services/modpack-manager/Cargo.toml new file mode 100644 index 0000000..0f0981c --- /dev/null +++ b/services/modpack-manager/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "minecrarch-modpack-manager" +version = "0.1.0" +edition = "2021" +license = "MIT OR Apache-2.0" + +[[bin]] +name = "minecrarch-modpack-manager" +path = "src/main.rs" + +[dependencies] +zbus = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } +tracing-subscriber = { workspace = true, features = ["env-filter", "json"] } +minecrarch-shared = { path = "../../shared", version = "0.1" } diff --git a/services/modpack-manager/src/main.rs b/services/modpack-manager/src/main.rs new file mode 100644 index 0000000..6f13d69 --- /dev/null +++ b/services/modpack-manager/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("minecrarch-modpack-manager stub — Phase 1 D5 will replace this"); +} diff --git a/shared/Cargo.toml b/shared/Cargo.toml new file mode 100644 index 0000000..94a550c --- /dev/null +++ b/shared/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "minecrarch-shared" +version = "0.1.0" +edition = "2021" +license = "MIT OR Apache-2.0" + +[dependencies] +thiserror = { workspace = true } diff --git a/shared/src/dbus_types.rs b/shared/src/dbus_types.rs new file mode 100644 index 0000000..22f94c6 --- /dev/null +++ b/shared/src/dbus_types.rs @@ -0,0 +1,40 @@ +//! D-Bus type aliases and constants for MinecrarchOS IPC. +//! Full interface contracts are defined in docs/ipc.md. +//! Instance and snapshot data are passed as D-Bus dicts (a{sv}) per the IPC spec. + +/// Field keys for an instance dict (`ListInstances` return type). D-Bus type: `a{sv}`. +pub mod instance_fields { + pub const ID: &str = "id"; + pub const NAME: &str = "name"; + pub const EDITION: &str = "edition"; + pub const VERSION: &str = "version"; + pub const STATUS: &str = "status"; +} + +/// Field keys for a snapshot dict (ListSnapshots return type). +/// D-Bus type: a{sv} with these keys. +pub mod snapshot_fields { + pub const ID: &str = "id"; + pub const TIMESTAMP: &str = "timestamp"; + pub const VERSION: &str = "version"; + pub const SIZE_BYTES: &str = "size_bytes"; +} + +/// D-Bus error name prefix for all MinecrarchOS errors. +pub const ERROR_NAMESPACE: &str = "org.minecrarch.Error"; + +/// D-Bus bus names for all platform services. +pub mod bus_names { + pub const MODPACK_MANAGER: &str = "org.minecrarch.ModpackManager"; + pub const OVERLAY: &str = "org.minecrarch.Overlay"; + pub const UPDATER: &str = "org.minecrarch.Updater"; + pub const LOGGING: &str = "org.minecrarch.Logging"; +} + +/// D-Bus object paths for all platform services. +pub mod object_paths { + pub const MODPACK_MANAGER: &str = "/org/minecrarch/ModpackManager"; + pub const OVERLAY: &str = "/org/minecrarch/Overlay"; + pub const UPDATER: &str = "/org/minecrarch/Updater"; + pub const LOGGING: &str = "/org/minecrarch/Logging"; +} diff --git a/shared/src/error.rs b/shared/src/error.rs new file mode 100644 index 0000000..c050000 --- /dev/null +++ b/shared/src/error.rs @@ -0,0 +1,19 @@ +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum MinecrarchError { + #[error("IPC error: {0}")] + Ipc(String), + + #[error("Launch failed: {0}")] + Launch(String), + + #[error("Install failed: {0}")] + Install(String), + + #[error("Instance not found: {0}")] + InstanceNotFound(String), + + #[error("IO error: {0}")] + Io(#[from] std::io::Error), +} diff --git a/shared/src/lib.rs b/shared/src/lib.rs new file mode 100644 index 0000000..4ac8865 --- /dev/null +++ b/shared/src/lib.rs @@ -0,0 +1,4 @@ +/// Shared types, constants, and error definitions for MinecrarchOS components. +/// All IPC contracts are defined in docs/ipc.md. +pub mod dbus_types; +pub mod error; diff --git a/shell/Cargo.toml b/shell/Cargo.toml new file mode 100644 index 0000000..87312e6 --- /dev/null +++ b/shell/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "minecrarch-shell" +version = "0.1.0" +edition = "2021" +license = "MIT OR Apache-2.0" + +[[bin]] +name = "minecrarch-shell" +path = "src/main.rs" + +[dependencies] +gtk4 = { version = "0.9", features = ["v4_12"] } +libadwaita = { version = "0.7", features = ["v1_5"] } +zbus = { workspace = true } +tokio = { workspace = true } +async-channel = "2" +tracing = { workspace = true } +tracing-subscriber = { workspace = true, features = ["env-filter", "json"] } +minecrarch-shared = { path = "../shared", version = "0.1" } diff --git a/shell/src/main.rs b/shell/src/main.rs new file mode 100644 index 0000000..acaa7d8 --- /dev/null +++ b/shell/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("minecrarch-shell stub — Phase 1 D4 will replace this"); +} diff --git a/tools/check-deps.sh b/tools/check-deps.sh index 5e0febb..f8928f1 100755 --- a/tools/check-deps.sh +++ b/tools/check-deps.sh @@ -24,7 +24,9 @@ check_cargo_toml() { fi for dep in "${forbidden[@]}"; do - if grep -q "\"${dep}\"" "$file" || grep -q "'${dep}'" "$file"; then + # Match only dependency declarations (lines like `crate-name = ...` or `crate-name = { ... }`) + # Excludes [package] name = "..." lines by requiring the crate name at line start + if grep -qE "^[[:space:]]*${dep}[[:space:]]*(=|\\.)" "$file"; then fail "${component} (${file}) must not depend on ${dep}" fi done