Fix audit findings: bakery index signing, artifact checksums, stale theme docs
- Add minisign-based signing/verification for the bakery index: scripts/gen-index.sh signs index.json (MINISIGN_SEC_KEY env var, dormant no-op with a loud warning until a key is provisioned); bakery/src/manifest.rs fetches index.json.minisig and verifies it with minisign-verify against a hardcoded PUBKEY before parsing/caching, and re-verifies the cached copy on every load (falls back to one re-fetch if the cache predates signing or fails verification; a fresh fetch that fails verification is a hard error). - Close the previously-unchecksummed config-example and systemd-unit downloads in bakery/src/install.rs (scaffold_config, install_service): index.json now carries `sha256`/`example_sha256` for these artifacts (computed in gen-index.sh), verified via the same download::verify_sha256 used for binaries. Downloads without a matching sha256 in the index are refused rather than installed unverified. - scripts/get.sh now verifies the bakery release binary itself against a pinned minisign public key before installing it (falls back to the existing sha256-only check with a loud warning if no .minisig is published yet or minisign isn't installed; a present-but-invalid signature is a hard failure). - Add dormant "sign release binary" steps to the bakery and bread-theme release workflows (.github/workflows/release.yml, .forgejo/workflows/release-bread-theme.yml), gated on secrets that are not yet configured — binaries ship unsigned exactly as before until the owner wires up the secret. - .gitignore: add *.minisign-sec / minisign.key so the signing key can never be committed by accident. - bread-theme: fix stale docs describing a "Catppuccin Mocha fallback" (BREAD_DESIGN_SYSTEM.md, README.md, Cargo.toml/bakery.toml/registry descriptions) — the actual implementation (palette.rs) uses a fixed BOS dark base with only accent colors from pywal. - bread-theme: fix the legacy css_vars() path, which had its own hand-written @define-color block that predated the `accent` and computed `on-*` ink colors used by the rest of the stylesheet — any caller whose CSS referenced those names against css_vars()'s output would hit undefined colors (the illegible-text bug). css_vars() now delegates to the same define_colors() the full stylesheet uses, so the two can't drift apart again.
This commit is contained in:
parent
fa0597f482
commit
394a252f9e
18 changed files with 472 additions and 84 deletions
|
|
@ -4,7 +4,7 @@ version.workspace = true
|
|||
edition.workspace = true
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
description = "Shared pywal + Catppuccin theming crate for the bread ecosystem"
|
||||
description = "Shared pywal-accented, fixed-dark-base theming crate for the bread ecosystem"
|
||||
repository = "https://github.com/Breadway/bread-ecosystem"
|
||||
keywords = ["theming", "pywal", "gtk4", "wayland"]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
name = "bread-theme"
|
||||
description = "Shared pywal + Catppuccin theming CLI for the bread ecosystem — generates the shared GTK4 stylesheet every bread app loads"
|
||||
description = "Shared pywal-accented, fixed-dark-base theming CLI for the bread ecosystem — generates the shared GTK4 stylesheet every bread app loads"
|
||||
binaries = ["bread-theme"]
|
||||
system_deps = []
|
||||
optional_system_deps = ["python-pywal"]
|
||||
|
|
|
|||
|
|
@ -24,31 +24,23 @@ pub mod tokens {
|
|||
pub const RADIUS_PILL: u16 = 999;
|
||||
}
|
||||
|
||||
/// Emit the `@define-color` block that all bread apps use.
|
||||
/// Apps append their own rules below this; user CSS goes on top.
|
||||
/// Emit the `@define-color` block that all bread apps use, plus the shared
|
||||
/// font rule.
|
||||
///
|
||||
/// Kept for API compatibility with older callers that only want the color
|
||||
/// variables (not the full [`stylesheet`] component rules). It used to carry
|
||||
/// its own hand-written `@define-color` block that predated the `accent` and
|
||||
/// computed-ink (`on-*`) colors — that duplication is exactly what let it
|
||||
/// drift out of sync and reintroduce the illegible-text bug (light pywal
|
||||
/// colors + no computed ink meant white-on-white / black-on-black text
|
||||
/// wherever a caller's own CSS referenced `@on-surface`, `@on-accent`, etc.,
|
||||
/// since those names simply didn't exist in this block). It now delegates
|
||||
/// to the same [`define_colors`] the full stylesheet uses, so there is only
|
||||
/// one color-block implementation and it cannot drift again.
|
||||
pub fn css_vars(p: &Palette) -> String {
|
||||
format!(
|
||||
"@define-color bg {bg};\n\
|
||||
@define-color fg {fg};\n\
|
||||
@define-color surface {c0};\n\
|
||||
@define-color red {c1};\n\
|
||||
@define-color green {c2};\n\
|
||||
@define-color yellow {c3};\n\
|
||||
@define-color blue {c4};\n\
|
||||
@define-color pink {c5};\n\
|
||||
@define-color teal {c6};\n\
|
||||
@define-color overlay {c7};\n\
|
||||
* {{ font-family: '{font}'; font-size: {size}px; }}\n",
|
||||
bg = p.background,
|
||||
fg = p.foreground,
|
||||
c0 = p.color0,
|
||||
c1 = p.color1,
|
||||
c2 = p.color2,
|
||||
c3 = p.color3,
|
||||
c4 = p.color4,
|
||||
c5 = p.color5,
|
||||
c6 = p.color6,
|
||||
c7 = p.color7,
|
||||
"{vars}* {{ font-family: '{font}'; font-size: {size}px; }}\n",
|
||||
vars = define_colors(p),
|
||||
font = tokens::FONT_FAMILY,
|
||||
size = tokens::FONT_SIZE_BASE,
|
||||
)
|
||||
|
|
@ -241,6 +233,33 @@ mod tests {
|
|||
assert!(css.contains("14px"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn css_vars_includes_accent_and_computed_ink_colors() {
|
||||
// Regression test: css_vars() used to be a second, hand-written
|
||||
// @define-color block that predated `accent` and the computed `on-*`
|
||||
// ink colors. Any caller whose own CSS referenced `@on-surface` /
|
||||
// `@on-accent` etc. against that older block would hit an undefined
|
||||
// color name — the illegible-text bug. css_vars() must now emit
|
||||
// exactly the same color set as the full stylesheet.
|
||||
let css = css_vars(&Palette::default());
|
||||
for name in &["accent", "on-bg", "on-surface", "on-accent", "on-red", "on-overlay"] {
|
||||
assert!(css.contains(&format!("@define-color {name} ")), "missing @define-color {name}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn css_vars_and_stylesheet_agree_on_color_block() {
|
||||
// Both must derive their color variables from the same
|
||||
// `define_colors` implementation, so they can't drift apart again.
|
||||
let p = Palette::default();
|
||||
let vars = css_vars(&p);
|
||||
let sheet = stylesheet(&p);
|
||||
for name in &["bg", "fg", "surface", "overlay", "accent", "on-bg", "on-surface", "on-accent"] {
|
||||
let needle = format!("@define-color {name} ");
|
||||
assert!(vars.contains(&needle) && sheet.contains(&needle));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stylesheet_defines_canonical_colors_and_components() {
|
||||
let css = stylesheet(&Palette::default());
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue