-
Notifications
You must be signed in to change notification settings - Fork 0
chore(just): adopt shared phenotype.just recipe library #49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,195 @@ | ||
| # phenotype.just — shared recipe library for Phenotype-org repositories | ||
| # | ||
| # Usage (in a consumer repo's justfile): | ||
| # import "phenotype.just" | ||
| # | ||
| # All recipes here are workspace-agnostic; they auto-detect the build system | ||
| # (cargo / npm / pnpm / yarn / bun / uv / poetry / go / mix) and run the | ||
| # appropriate command. Recipes that are stack-specific (e.g. `register-startmenu` | ||
| # for Electrobun) live in the consumer's justfile, NOT here. | ||
| # | ||
| # Versioning: SemVer. Breaking a recipe signature is a major bump. | ||
|
|
||
| # === variables === | ||
|
|
||
| # Detect the build system by walking up from the justfile dir. | ||
| # Returns one of: cargo | npm | pnpm | yarn | bun | uv | poetry | go | mix | none | ||
| build_system := `\ | ||
| if [ -f Cargo.toml ]; then echo cargo; \ | ||
| elif [ -f package.json ] && [ -f pnpm-lock.yaml ]; then echo pnpm; \ | ||
| elif [ -f package.json ] && [ -f yarn.lock ]; then echo yarn; \ | ||
| elif [ -f package.json ] && [ -f bun.lockb ]; then echo bun; \ | ||
| elif [ -f package.json ] && [ -f bun.lock ]; then echo bun; \ | ||
| elif [ -f package.json ]; then echo npm; \ | ||
| elif [ -f pyproject.toml ] && [ -f uv.lock ]; then echo uv; \ | ||
| elif [ -f pyproject.toml ] && [ -f poetry.lock ]; then echo poetry; \ | ||
| elif [ -f pyproject.toml ]; then echo uv; \ | ||
| elif [ -f go.mod ]; then echo go; \ | ||
| elif [ -f mix.exs ]; then echo mix; \ | ||
| else echo none; fi` | ||
|
|
||
| # Recipe to invoke for "build". | ||
| build_cmd := if build_system == "cargo" { "cargo build --workspace" } \ | ||
| else if build_system == "pnpm" { "pnpm -r build" } \ | ||
| else if build_system == "yarn" { "yarn workspaces run build" } \ | ||
| else if build_system == "bun" { "bun run build" } \ | ||
| else if build_system == "npm" { "npm run build --workspaces --if-present" } \ | ||
| else if build_system == "uv" { "uv sync --all-extras" } \ | ||
| else if build_system == "poetry" { "poetry install --all-extras" } \ | ||
| else if build_system == "go" { "go build ./..." } \ | ||
| else if build_system == "mix" { "mix compile" } \ | ||
| else { "echo 'no build system detected' && exit 1" } | ||
|
|
||
| # Recipe to invoke for "test". | ||
| test_cmd := if build_system == "cargo" { "cargo test --workspace" } \ | ||
| else if build_system == "pnpm" { "pnpm -r test" } \ | ||
| else if build_system == "yarn" { "yarn workspaces run test" } \ | ||
| else if build_system == "bun" { "bun test" } \ | ||
| else if build_system == "npm" { "npm test --workspaces --if-present" } \ | ||
| else if build_system == "uv" { "uv run pytest" } \ | ||
| else if build_system == "poetry" { "poetry run pytest" } \ | ||
| else if build_system == "go" { "go test ./..." } \ | ||
| else if build_system == "mix" { "mix test" } \ | ||
| else { "echo 'no test runner detected' && exit 1" } | ||
|
|
||
| # Recipe to invoke for "lint". | ||
| lint_cmd := if build_system == "cargo" { "cargo clippy --workspace --all-targets -- -D warnings && cargo fmt --check" } \ | ||
| else if build_system == "pnpm" { "pnpm -r lint && pnpm -r format:check" } \ | ||
| else if build_system == "yarn" { "yarn workspaces run lint" } \ | ||
| else if build_system == "bun" { "bun run lint" } \ | ||
| else if build_system == "npm" { "npm run lint --workspaces --if-present" } \ | ||
| else if build_system == "uv" { "uv run ruff check . && uv run ruff format --check ." } \ | ||
| else if build_system == "poetry" { "poetry run ruff check . && poetry run ruff format --check ." } \ | ||
| else if build_system == "go" { "go vet ./... && gofmt -l ." } \ | ||
| else if build_system == "mix" { "mix format --check-formatted && mix credo --strict" } \ | ||
| else { "echo 'no linter detected' && exit 1" } | ||
|
|
||
| # === core recipes === | ||
|
|
||
| # Default: list recipes. | ||
| default: | ||
| @just --list -u | ||
|
|
||
| # Build the workspace. | ||
| build: | ||
| {{build_cmd}} | ||
|
|
||
| # Run the test suite. | ||
| test: | ||
| {{test_cmd}} | ||
|
|
||
| # Lint (linter + formatter check). | ||
| lint: | ||
| {{lint_cmd}} | ||
|
|
||
| # Auto-format all files in place. | ||
| fmt: | ||
| @just _fmt | ||
|
|
||
| # Stack-specific formatters. | ||
| _fmt: | ||
| @if [ "{{build_system}}" = "cargo" ]; then cargo fmt; \ | ||
| elif [ "{{build_system}}" = "pnpm" ]; then pnpm -r format; \ | ||
| elif [ "{{build_system}}" = "yarn" ]; then yarn workspaces run format; \ | ||
| elif [ "{{build_system}}" = "bun" ]; then bun run fmt; \ | ||
| elif [ "{{build_system}}" = "npm" ]; then npm run format --workspaces --if-present; \ | ||
| elif [ "{{build_system}}" = "uv" ]; then uv run ruff format .; \ | ||
| elif [ "{{build_system}}" = "poetry" ]; then poetry run ruff format .; \ | ||
| elif [ "{{build_system}}" = "go" ]; then gofmt -w .; \ | ||
| elif [ "{{build_system}}" = "mix" ]; then mix format; \ | ||
| else echo "no formatter detected for {{build_system}}"; fi | ||
|
|
||
| # Security audits. Stack-specific. | ||
| audit: | ||
| @just _audit | ||
|
|
||
| _audit: | ||
| @if [ "{{build_system}}" = "cargo" ]; then \ | ||
| (command -v cargo-deny >/dev/null && cargo deny check || echo "cargo-deny not installed; skip") && \ | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: The cargo-deny branch treats any non-zero exit from Severity Level: Critical 🚨- ❌ `just audit` never fails on cargo-deny findings.
- ⚠️ `just ci` reports success despite deny vulnerabilities.
- ⚠️ Local security workflows relying on just get false assurance.Steps of Reproduction ✅1. From the repository root `/workspace/Tasken`, run `just audit`; the entrypoint Justfile
at `justfile:14` imports `just/phenotype.just` defining the `audit` recipe at
`just/phenotype.just:102-116`.
2. Because `Cargo.toml` exists at the repo root (`/workspace/Tasken/Cargo.toml`), the
`build_system` variable at `just/phenotype.just:17-29` resolves to `"cargo"`.
3. The `audit` recipe calls `_audit` (`just/phenotype.just:106`), which in the cargo
branch executes line `108` `(command -v cargo-deny >/dev/null && cargo deny check || echo
"cargo-deny not installed; skip") && \`.
4. With `cargo-deny` installed and configured (see `deny.toml` at
`/workspace/Tasken/deny.toml`), if `cargo deny check` detects a violation it exits
non-zero; this makes `command -v ... && cargo deny check` as a whole fail, triggering the
`|| echo "cargo-deny not installed; skip"` part, which returns exit code 0 so `_audit`,
`audit`, and transitively `ci` (`just/phenotype.just:145`) all succeed even though the
deny check failed.Fix in Cursor | Fix in VSCode Claude (Use Cmd/Ctrl + Click for best experience) Prompt for AI Agent 🤖This is a comment left during a code review.
**Path:** just/phenotype.just
**Line:** 108:108
**Comment:**
*Security: The cargo-deny branch treats any non-zero exit from `cargo deny check` as if the tool were missing because of `... && cargo deny check || echo ...`. That masks real vulnerability failures and makes `just audit`/`just ci` pass when they should fail. Split the "tool installed" check from the command execution so actual audit findings propagate a non-zero exit code.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix |
||
| (command -v cargo-audit >/dev/null && cargo audit || echo "cargo-audit not installed; skip"); \ | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Installed audit failures exit zeroHigh Severity The cargo Additional Locations (2)Reviewed by Cursor Bugbot for commit 6486ae7. Configure here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: The Severity Level: Critical 🚨- ❌ `just audit` ignores non-zero cargo-audit vulnerability exits.
- ⚠️ `just ci` gives green status despite RustSec advisories.
- ⚠️ Developers running just locally get misleading security results.Steps of Reproduction ✅1. From `/workspace/Tasken`, run `just audit`; `justfile:14` imports
`just/phenotype.just`, where `audit` and `_audit` are defined at
`just/phenotype.just:102-116`.
2. With `Cargo.toml` present, `build_system` resolves to `"cargo"`
(`just/phenotype.just:17-29`), so `_audit` takes the cargo branch (line 107) and executes
the cargo-audit command at line 109: `(command -v cargo-audit >/dev/null && cargo audit ||
echo "cargo-audit not installed; skip");`.
3. When `cargo-audit` is installed (validated by `command -v cargo-audit >/dev/null`) and
it finds vulnerable dependencies, the `cargo audit` process exits with a non-zero status,
causing the `command -v ... && cargo audit` part to fail.
4. That failure triggers the `|| echo "cargo-audit not installed; skip"` portion, which
prints the skip message and exits 0, so `_audit`, `audit`, and any `just ci` invocation
(`just/phenotype.just:145`) all report success even when `cargo-audit` actually detected
vulnerabilities; current GitHub workflows run `cargo-audit` separately
(`.github/workflows/cargo-audit.yml`) so CI still catches issues, but the Just-based flow
is incorrect.Fix in Cursor | Fix in VSCode Claude (Use Cmd/Ctrl + Click for best experience) Prompt for AI Agent 🤖This is a comment left during a code review.
**Path:** just/phenotype.just
**Line:** 109:109
**Comment:**
*Security: The `cargo audit` invocation has the same masking pattern: if `cargo audit` finds vulnerabilities and exits non-zero, the `|| echo ...` branch runs and returns success. This causes security checks to silently pass despite detected issues, so preserve non-zero exit codes from the audit tool.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix |
||
| elif [ "{{build_system}}" = "uv" ] || [ "{{build_system}}" = "poetry" ]; then \ | ||
| uv run pip-audit 2>/dev/null || poetry run pip-audit 2>/dev/null || echo "pip-audit not installed; skip"; \ | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Poetry path runs uv firstMedium Severity Branches keyed on Additional Locations (1)Reviewed by Cursor Bugbot for commit 6486ae7. Configure here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: The Python audit fallback chain conflates "tool missing" with "audit failed": a real Severity Level: Critical 🚨- ❌ Python `just audit` can never fail on pip-audit issues.
- ⚠️ `just ci` in Python stacks silently skips dependency vulnerabilities.
- ⚠️ Security posture weaker for uv/poetry-based Phenotype repositories.Steps of Reproduction ✅1. In a Phenotype repo that imports `just/phenotype.just` in its justfile and has a Python
project layout (e.g. `pyproject.toml` and `uv.lock` so `build_system` resolves to `"uv"`
or `"poetry"` via `just/phenotype.just:24-26`), run `just audit`.
2. The `audit` recipe (`just/phenotype.just:102-105`) delegates to `_audit`
(`just/phenotype.just:106-116`); for `build_system` `"uv"` or `"poetry"`, line 110 chooses
the Python branch.
3. Line 111 executes `uv run pip-audit 2>/dev/null || poetry run pip-audit 2>/dev/null ||
echo "pip-audit not installed; skip";`: if `uv run pip-audit` is available and detects
vulnerabilities, `pip-audit` exits non-zero, causing the whole `uv run pip-audit` command
to fail and the shell to fall through to `poetry run pip-audit` instead of failing.
4. If the poetry-based invocation is missing or also returns non-zero (e.g. more
vulnerabilities or failures), the pipeline falls through again to `echo "pip-audit not
installed; skip"`, which exits 0 and makes `_audit`, `audit`, and `ci`
(`just/phenotype.just:145`) succeed even though a Python auditor actually reported
dependency vulnerabilities.Fix in Cursor | Fix in VSCode Claude (Use Cmd/Ctrl + Click for best experience) Prompt for AI Agent 🤖This is a comment left during a code review.
**Path:** just/phenotype.just
**Line:** 111:111
**Comment:**
*Security: The Python audit fallback chain conflates "tool missing" with "audit failed": a real `pip-audit` failure from `uv run` can fall through to `poetry run` and then to `echo`, returning success. This suppresses detected vulnerabilities in CI. Check tool availability first, then run exactly one auditor and propagate its exit status.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix |
||
| elif [ "{{build_system}}" = "pnpm" ]; then pnpm audit --prod; \ | ||
| elif [ "{{build_system}}" = "bun" ]; then bun audit; \ | ||
| elif [ "{{build_system}}" = "npm" ]; then npm audit --omit=dev; \ | ||
| elif [ "{{build_system}}" = "go" ]; then govulncheck ./... 2>/dev/null || echo "govulncheck not installed; skip"; \ | ||
| else echo "no audit tool for {{build_system}}"; fi | ||
|
Comment on lines
+107
to
+116
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The current shell logic for checking and running audit tools uses the We should use an explicit For |
||
|
|
||
| # Find unused dependencies. Stack-specific. | ||
| unused: | ||
| @just _unused | ||
|
|
||
| _unused: | ||
| @if [ "{{build_system}}" = "cargo" ]; then \ | ||
| (command -v cargo-machete >/dev/null && cargo machete || echo "cargo-machete not installed; skip"); \ | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: The unused-dependency check for cargo masks real findings: if Severity Level: Major
|
||
| elif [ "{{build_system}}" = "uv" ] || [ "{{build_system}}" = "poetry" ]; then \ | ||
| uv run deptry . 2>/dev/null || poetry run deptry . 2>/dev/null || echo "deptry not installed; skip"; \ | ||
| elif [ "{{build_system}}" = "pnpm" ]; then pnpm dlx depcheck; \ | ||
| else echo "no unused-dep tool for {{build_system}}"; fi | ||
|
Comment on lines
+123
to
+128
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar to the We should use explicit |
||
|
|
||
| # Type-check. Stack-specific. | ||
| typecheck: | ||
| @just _typecheck | ||
|
|
||
| _typecheck: | ||
| @if [ "{{build_system}}" = "cargo" ]; then cargo check --workspace --all-targets; \ | ||
| elif [ "{{build_system}}" = "uv" ] || [ "{{build_system}}" = "poetry" ]; then \ | ||
| (uv run mypy . 2>/dev/null || poetry run mypy . 2>/dev/null || echo "mypy not installed; skip"); \ | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: The mypy typecheck command has the same logic bug: type errors from Severity Level: Major
|
||
| elif [ "{{build_system}}" = "pnpm" ]; then pnpm -r typecheck; \ | ||
| elif [ "{{build_system}}" = "bun" ]; then bun run typecheck 2>/dev/null || echo "no typecheck script"; \ | ||
| elif [ "{{build_system}}" = "npm" ]; then npm run typecheck --workspaces --if-present; \ | ||
| elif [ "{{build_system}}" = "go" ]; then go build ./... && go vet ./...; \ | ||
| else echo "no typechecker for {{build_system}}"; fi | ||
|
Comment on lines
+135
to
+142
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
We should check for tool/script existence first before running them. For |
||
|
|
||
| # Full local CI sweep: lint + test + audit + unused + typecheck. | ||
| ci: lint typecheck test audit unused | ||
| @echo "✓ all CI checks passed" | ||
|
|
||
| # Generate docs. | ||
| docs: | ||
| @just _docs | ||
|
|
||
| _docs: | ||
| @if [ "{{build_system}}" = "cargo" ]; then cargo doc --no-deps --workspace; \ | ||
| elif [ "{{build_system}}" = "uv" ] || [ "{{build_system}}" = "poetry" ]; then \ | ||
| uv run sphinx-build -b html docs/ docs/_build/ 2>/dev/null || \ | ||
| poetry run sphinx-build -b html docs/ docs/_build/ 2>/dev/null || \ | ||
| echo "no sphinx config; skip"; \ | ||
| else echo "no doc generator for {{build_system}}"; fi | ||
|
Comment on lines
+153
to
+158
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The We should check if |
||
|
|
||
| # === developer-experience recipes === | ||
|
|
||
| # Watch mode: rebuild on change. Stack-specific. | ||
| dev: | ||
| @just _dev | ||
|
|
||
| _dev: | ||
| @if [ "{{build_system}}" = "cargo" ]; then \ | ||
| (command -v cargo-watch >/dev/null && cargo watch -x build -x test || \ | ||
| echo "cargo-watch not installed; install with: cargo install cargo-watch"); \ | ||
| elif [ "{{build_system}}" = "bun" ]; then bun run dev; \ | ||
| elif [ "{{build_system}}" = "pnpm" ]; then pnpm -r dev; \ | ||
| elif [ "{{build_system}}" = "npm" ]; then npm run dev --workspaces --if-present; \ | ||
| else echo "no dev script for {{build_system}}"; fi | ||
|
Comment on lines
+167
to
+173
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The We should use an explicit |
||
|
|
||
| # Clean build artifacts. | ||
| clean: | ||
| @just _clean | ||
|
|
||
| _clean: | ||
| @if [ "{{build_system}}" = "cargo" ]; then cargo clean; \ | ||
| elif [ "{{build_system}}" = "uv" ] || [ "{{build_system}}" = "poetry" ]; then \ | ||
| rm -rf .venv dist build *.egg-info .pytest_cache .mypy_cache .ruff_cache; \ | ||
| elif [ "{{build_system}}" = "pnpm" ]; then pnpm clean 2>/dev/null || rm -rf node_modules; \ | ||
| elif [ "{{build_system}}" = "bun" ]; then rm -rf node_modules dist build; \ | ||
| elif [ "{{build_system}}" = "npm" ]; then rm -rf node_modules dist build; \ | ||
| elif [ "{{build_system}}" = "go" ]; then go clean -cache -testcache; \ | ||
| elif [ "{{build_system}}" = "mix" ]; then mix clean; \ | ||
| else rm -rf build dist; fi | ||
|
|
||
| # Print detected build system (debug). | ||
| info: | ||
| @echo "build_system={{build_system}}" | ||
| @echo "build_cmd={{build_cmd}}" | ||
| @echo "test_cmd={{test_cmd}}" | ||
| @echo "lint_cmd={{lint_cmd}}" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,29 +1,16 @@ | ||
| # Phenotype-org standard justfile | ||
| # Tasken Justfile | ||
| # | ||
| # After 2026-06-11, this justfile is a thin shell that re-exports the shared | ||
| # `phenotype.just` library (defined in just/phenotype.just). The 9 most | ||
| # common recipes (default, build, test, lint, fmt, audit, unused, ci, docs) | ||
| # are now defined once in the library and parameterized over the build | ||
| # system. | ||
| # | ||
| # Stack-specific recipes (e.g. `clean`, `dev`) stay in this file. | ||
| # | ||
| # To upgrade: pull the latest phenotype.just from the central repo, or | ||
| # vendor it as a git submodule. | ||
|
|
||
| import "just/phenotype.just" | ||
|
|
||
| default: | ||
| @just --list | ||
|
|
||
| build: | ||
| cargo build --workspace | ||
|
|
||
| test: | ||
| cargo test --workspace | ||
|
|
||
| lint: | ||
| cargo clippy --workspace -- -D warnings | ||
| cargo fmt --check | ||
|
|
||
| fmt: | ||
| cargo fmt | ||
|
|
||
| audit: | ||
| cargo deny check | ||
| cargo audit | ||
|
|
||
| unused: | ||
| cargo machete | ||
|
|
||
| ci: lint test audit unused | ||
|
|
||
| docs: | ||
| cargo doc --no-deps --workspace |


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Go lint ignores formatting drift
Medium Severity
For the
gobuild system,lint_cmdends withgofmt -l ., which lists unformatted files but exits 0 even when output is non-empty, sojust lintandjust cido not fail on formatting violations unlike other stacks that use explicit format checks.Reviewed by Cursor Bugbot for commit 6486ae7. Configure here.