Skip to content

chore: adopt devkit baseline (CI, security, JSR publish hygiene) - #4

Merged
RickCogley merged 3 commits into
mainfrom
feat/devkit-baseline
Apr 29, 2026
Merged

chore: adopt devkit baseline (CI, security, JSR publish hygiene)#4
RickCogley merged 3 commits into
mainfrom
feat/devkit-baseline

Conversation

@RickCogley

Copy link
Copy Markdown
Member

Summary

Implements the punch list from #3. Closes #3.

Critical fix: deno.json was missing publish.include/exclude, so every JSR install of @esolia/marquis was pulling the entire repo (assets/, docs/, docs-site/, examples/) into the package. Now bundles only the public surface — mod.ts, index.ts, ui/**, tokens/**, utils/**, assets/*.ts (typed wrappers, no raw SVGs), README.md, LICENSE.

What's in this PR

CI/CD (none previously)

  • ci.yml — fmt/lint/check/test/publish-dry on PR/main
  • publish.yml — tag-triggered (v*) JSR publish with provenance
  • security.yml — calls eSolia/devkit/.github/workflows/secrets-and-sast.yml@main directly. Same-org call, no vendoring needed (the cross-org block we hit on RickCogley/* repos doesn't apply here)
  • dependabot.yml — weekly github-actions + npm (docs-site)

JSR / publish hygiene

  • publish.include/exclude blocks (the critical fix)
  • Renamed publish:dry task with --allow-slow-types
  • Same flag in publish.yml and ci.yml — tracked as debt (see "Out of scope")
  • --allow-slow-types is needed because ui/icon-button.ts has 13 symbols missing explicit types

Deno hygiene

  • Override the project .gitignore entry for deno.lock so the lockfile is committed (it was project-ignored on line 3, in addition to global)
  • Exclude assets/**/*.svg from deno fmt — was reformatting SVG XML on every preflight run, leaving 17 files modified
  • Commit deno.lock (JSR convention)

Tests

  • tests/api_surface_test.ts — 8 credential-free smoke tests covering the export surface (utility, token, UI, asset, favicon) plus basic behavior of cn(), getButtonClasses(), getBadgeClasses(). Replaces the empty tests/ dir.

Claude tooling

  • .claude/rules/change-management.md (copy from devkit shared-rules)

Doc cleanup (post-Deno-Deploy migration)

  • docs/CLAUDE-GUIDE.md — replaced 3 stale Deno Deploy references with Cloudflare Workers (the strategy table row for Periodic, the "Work directly with..." principle, and the "future Deno Deploy apps" mention).

Out of scope (flagged for separate decisions)

Item Why deferred
Root CLAUDE-GUIDE.md (795 lines) duplicates docs/CLAUDE-GUIDE.md (526 lines) — different content. The root version is the older/longer file; the docs/ version reads as a deliberate re-write. Needs your call on what to preserve. Recommend: keep docs/ as canonical (root CLAUDE.md already redirects there), then either merge missing content from root or delete root if the dropped content was intentional.
Untracked docs/marquis-design-system-strategy.md Looks like in-progress work — left alone.
ui/icon-button.ts slow types (13 symbols) Adding explicit types is mechanical but separate scope. --allow-slow-types carries us until then.

Test plan

  • deno fmt --check passes
  • deno lint passes
  • deno check mod.ts passes
  • deno test --allow-read — 8 passed, 0 failed
  • deno publish --dry-run --allow-slow-types succeeds — bundle is the right shape (no docs, no docs-site, no raw SVGs)
  • CI workflow runs green on this PR
  • Security workflow runs green on this PR (first SAST/secrets/SBOM run for marquis)

InfoSec: brings continuous SAST + secret scanning + SBOM to a repo that previously had zero security automation. Tightening publish.include/exclude also reduces accidental disclosure of internal docs (kickoff designs, strategy markdown) into the public JSR package.

…de rules)

Implements the punch list from issue #3.

JSR publishing (critical):
- Add publish.include/exclude to deno.json — currently the package was
  shipping the entire repo (assets/, docs/, docs-site/, examples/) into
  every JSR install. Bundle now contains only mod.ts, index.ts, ui/**,
  tokens/**, utils/**, assets/*.ts (typed wrappers, not raw SVGs),
  README.md, and LICENSE. Verified with `deno publish --dry-run`.
- Add `--allow-slow-types` to publish task and workflows. Tracked as debt:
  ui/icon-button.ts has 13 symbols (icons object literal, searchIcon,
  etc.) missing explicit type annotations. Fixing them is a separate PR.

CI/CD (none previously):
- Add .github/workflows/ci.yml — fmt/lint/check/test/publish-dry on
  PR/main pushes
- Add .github/workflows/publish.yml — tag-triggered (v*) publish to JSR
  with provenance via id-token: write
- Add .github/workflows/security.yml — direct caller of
  eSolia/devkit/.github/workflows/secrets-and-sast.yml@main. Same-org
  call (eSolia → eSolia) so no vendoring needed (unlike the
  RickCogley/* repos which had to vendor — see RickCogley/tedasuke#3)
- Add .github/dependabot.yml — weekly github-actions + npm (docs-site/)
  updates

Deno hygiene:
- Add `preflight` and `publish:dry` tasks
- Override the project .gitignore entry for deno.lock so the lockfile is
  committed (was line 3 of the project gitignore in addition to global)
- Commit deno.lock for reproducibility (JSR convention)
- Exclude assets/**/*.svg from `deno fmt` — was reformatting SVG XML on
  every preflight run, which is unintended (SVG belongs to svgo)

Tests:
- Add tests/api_surface_test.ts — 8 credential-free smoke tests covering
  utility, token, UI component, asset, and favicon export surfaces, plus
  basic behavior checks for cn(), getButtonClasses(), getBadgeClasses().
  Replaces the empty tests directory so CI has something real to run.

Claude tooling:
- Add .claude/rules/change-management.md (copy from devkit shared-rules,
  adapted for marquis specifics — no `local/` subdirectory since this
  repo is not a devkit sync consumer)

Documentation cleanup (post-Deno-Deploy migration):
- docs/CLAUDE-GUIDE.md: replace 3 stale Deno Deploy references with
  Cloudflare Workers (the table row for Periodic, the "Work directly
  with..." principle line, and the "future Deno Deploy apps" mention).

Out of scope (flagged in PR):
- Root CLAUDE-GUIDE.md (795 lines) duplicates docs/CLAUDE-GUIDE.md (526
  lines). Different content — needs your call on what to preserve before
  consolidating.
- Untracked docs/marquis-design-system-strategy.md left alone (your
  in-progress work).
- ui/icon-button.ts slow types (13 symbols) — see above.

Closes #3

InfoSec: brings continuous SAST + secret scanning + SBOM to a repo that
previously had zero security automation. Tightening publish.include/exclude
also reduces accidental disclosure of internal docs (e.g. the strategy
markdown, kickoff designs in docs/) into the public JSR package.
Strip schedule + workflow_dispatch triggers and inline comments to
match the known-working esolia-llm-guard reference workflow exactly.
First push of the workflow failed at startup (0s, no jobs), and the
identical simpler pattern works for esolia-llm-guard, so isolating
the difference.

InfoSec: no functional change to security scanning — same scanners,
same source-paths, same secret pass-through.
Public-consumer + private-source mismatch: marquis is public,
eSolia/devkit is private. GitHub blocks public repos from calling
private reusable workflows even within the same org — same constraint
that applies cross-org. The first two attempts at a direct caller
failed at workflow startup (0s, no jobs).

Fix: vendor the workflow locally, matching the pattern used in
RickCogley/pub-cogley and RickCogley/tedasuke. Wrapper security.yml
now triggers a local secrets-and-sast-vendored.yml.

Also adds .gitignore override for global *secret* pattern, which
matches the vendored filename.

Updates the audit's mental model: the constraint isn't 'cross-org',
it's 'public consumer + private source'. eSolia/marquis hits this
within-org because of the visibility mismatch.

InfoSec: restores SAST + secret scanning + SBOM coverage. Vendored
copy is identical to the same upstream commit (c07c51c) used by
all other vendoring consumers.
@RickCogley

Copy link
Copy Markdown
Member Author

Update: had to vendor secrets-and-sast.yml here too. Originally I assumed the direct caller pattern (uses: eSolia/devkit/.github/workflows/secrets-and-sast.yml@main) would work for marquis since it's same-org as devkit (the same pattern works in eSolia/esolia-llm-guard).

It doesn't. Public consumer + private source is blocked, even within the same org. Marquis is public; devkit is private. GitHub blocks the call at startup (0s, no jobs created). esolia-llm-guard works because it's private+private, same org.

So the actual rule (corrected from my earlier comment on tedasuke#3) is:

  • ✅ private consumer + private source + same org → direct caller works (esolia-llm-guard)
  • ❌ private consumer + private source + cross-org → blocked, vendor (RickCogley/tedasuke, RickCogley/pub-cogley)
  • public consumer + private source + same org → blocked, vendor ← this PR
  • ❌ public consumer + private source + cross-org → blocked, vendor

The fix in latest commits (b53b860):

  • Added .github/workflows/secrets-and-sast-vendored.yml (verbatim copy of devkit's at SHA c07c51c, header rewritten with vendor metadata)
  • Changed .github/workflows/security.yml from a cross-org caller to a wrapper that triggers the local vendored workflow
  • Added .gitignore override for the global *secret* pattern (matches the vendored filename)

Also pulled the wrapper's extra triggers back in (schedule, workflow_dispatch) — those weren't the cause of the original failure, just things I temporarily stripped while debugging.

CI + Security workflows both green now. Note: the security workflow's display name still shows as .github/workflows/security.yml because GitHub cached the failed-startup state — should re-register as "Security" after merge.

@RickCogley
RickCogley merged commit 8ac7729 into main Apr 29, 2026
7 checks passed
@RickCogley
RickCogley deleted the feat/devkit-baseline branch April 29, 2026 05:57
RickCogley added a commit that referenced this pull request Apr 29, 2026
The publish workflow was added in #4 on the assumption marquis would
publish to JSR like tedasuke. Two facts that emerged after merge:

1. @esolia/marquis was never created on JSR (the v0.3.4 release tag
   fired publish.yml and it failed: 'Following packages don't exist').
2. The intended consumer (Periodic) has migrated off Deno entirely
   onto Cloudflare Workers and uses bits-ui for components, so there
   is no live consumer of marquis through any channel today.

Marquis is parked code; the GitHub releases (currently v0.3.4) are
sufficient version markers. No publish target needed.

CI and security workflows remain — they prevent bitrot if/when marquis
gets revived as a UI option for non-SvelteKit Workers apps.

InfoSec: no security impact — workflow removal only. Security scanning
(trivy/gitleaks/semgrep/syft via vendored secrets-and-sast workflow)
unaffected.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

chore: adopt devkit baseline (CI, security, Claude tooling)

1 participant