From 3b26bf36dbb73afad910a70f0fbea41ef3544e1e Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 26 Sep 2026 17:58:14 +0000 Subject: [PATCH 1/6] chore: lint YAML and GitHub Actions workflows Add yamllint and actionlint to the dev toolchain and run them from just dev_lint, which just lint, CI, and the pre-push hook already use. Co-authored-by: Michael Bianco --- .commitlintrc.yml | 1 - .config/mise.dev.lock | 53 +++++++++ .config/mise.dev.toml | 3 + .../mise.dev/yamllint/1.38.0/pyproject.toml | 5 + .../locks/mise.dev/yamllint/1.38.0/uv.lock | 103 ++++++++++++++++++ .github/actionlint-matcher.json | 17 +++ .github/actionlint.yml | 6 + .yamllint.yml | 27 +++++ just/dev.just | 24 +++- lefthook.yml | 2 + 10 files changed, 239 insertions(+), 2 deletions(-) create mode 100644 .config/mise/locks/mise.dev/yamllint/1.38.0/pyproject.toml create mode 100644 .config/mise/locks/mise.dev/yamllint/1.38.0/uv.lock create mode 100644 .github/actionlint-matcher.json create mode 100644 .github/actionlint.yml create mode 100644 .yamllint.yml diff --git a/.commitlintrc.yml b/.commitlintrc.yml index 4ca28f36..33b78d5a 100644 --- a/.commitlintrc.yml +++ b/.commitlintrc.yml @@ -5,4 +5,3 @@ rules: level: error # type-empty: # level: error - diff --git a/.config/mise.dev.lock b/.config/mise.dev.lock index dd525655..359caddf 100644 --- a/.config/mise.dev.lock +++ b/.config/mise.dev.lock @@ -2,6 +2,53 @@ lockfile_version = 2 +[[tools.actionlint]] +version = "1.7.12" +backend = "aqua:rhysd/actionlint" +specifiers = ["latest"] + +[tools.actionlint."platforms.linux-arm64"] +checksum = "sha256:325e971b6ba9bfa504672e29be93c24981eeb1c07576d730e9f7c8805afff0c6" +url = "https://github.com/rhysd/actionlint/releases/download/v1.7.12/actionlint_1.7.12_linux_arm64.tar.gz" +url_api = "https://api.github.com/repos/rhysd/actionlint/releases/assets/384924897" +provenance = "github-attestations" + +[tools.actionlint."platforms.linux-arm64-musl"] +checksum = "sha256:325e971b6ba9bfa504672e29be93c24981eeb1c07576d730e9f7c8805afff0c6" +url = "https://github.com/rhysd/actionlint/releases/download/v1.7.12/actionlint_1.7.12_linux_arm64.tar.gz" +url_api = "https://api.github.com/repos/rhysd/actionlint/releases/assets/384924897" +provenance = "github-attestations" + +[tools.actionlint."platforms.linux-x64"] +checksum = "sha256:8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8" +url = "https://github.com/rhysd/actionlint/releases/download/v1.7.12/actionlint_1.7.12_linux_amd64.tar.gz" +url_api = "https://api.github.com/repos/rhysd/actionlint/releases/assets/384924896" +provenance = "github-attestations" + +[tools.actionlint."platforms.linux-x64-musl"] +checksum = "sha256:8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8" +url = "https://github.com/rhysd/actionlint/releases/download/v1.7.12/actionlint_1.7.12_linux_amd64.tar.gz" +url_api = "https://api.github.com/repos/rhysd/actionlint/releases/assets/384924896" +provenance = "github-attestations" + +[tools.actionlint."platforms.macos-arm64"] +checksum = "sha256:aba9ced2dee8d27fecca3dc7feb1a7f9a52caefa1eb46f3271ea66b6e0e6953f" +url = "https://github.com/rhysd/actionlint/releases/download/v1.7.12/actionlint_1.7.12_darwin_arm64.tar.gz" +url_api = "https://api.github.com/repos/rhysd/actionlint/releases/assets/384924893" +provenance = "github-attestations" + +[tools.actionlint."platforms.macos-x64"] +checksum = "sha256:5b44c3bc2255115c9b69e30efc0fecdf498fdb63c5d58e17084fd5f16324c644" +url = "https://github.com/rhysd/actionlint/releases/download/v1.7.12/actionlint_1.7.12_darwin_amd64.tar.gz" +url_api = "https://api.github.com/repos/rhysd/actionlint/releases/assets/384924880" +provenance = "github-attestations" + +[tools.actionlint."platforms.windows-x64"] +checksum = "sha256:6e7241b51e6817ea6a047693d8e6fed13b31819c9a0dd6c5a726e1592d22f6e9" +url = "https://github.com/rhysd/actionlint/releases/download/v1.7.12/actionlint_1.7.12_windows_amd64.zip" +url_api = "https://api.github.com/repos/rhysd/actionlint/releases/assets/384924919" +provenance = "github-attestations" + [[tools.ast-grep]] version = "0.45.3" backend = "aqua:ast-grep/ast-grep" @@ -399,6 +446,12 @@ checksum = "sha256:aeabeecbd3eaad0bc8f555790eb7437ecd6cf1caae9bb93fb4e678f43f342 url = "https://github.com/watchexec/watchexec/releases/download/v2.7.2/watchexec-2.7.2-x86_64-pc-windows-msvc.zip" url_api = "https://api.github.com/repos/watchexec/watchexec/releases/assets/546730427" +[[tools.yamllint]] +version = "1.38.0" +backend = "pypi:yamllint" +specifiers = ["latest"] +uv = { path = "mise/locks/mise.dev/yamllint/1.38.0", digest = "sha256:ffd27c666e657c01a2185cfdeee7d8363d44c9d016e5d8cfcbfa3cb896291222" } + [[tools.yq]] version = "4.53.6" backend = "aqua:mikefarah/yq" diff --git a/.config/mise.dev.toml b/.config/mise.dev.toml index 950d6013..551faaaf 100644 --- a/.config/mise.dev.toml +++ b/.config/mise.dev.toml @@ -20,6 +20,9 @@ direnv = "latest" "github:peterldowns/localias" = "latest" "github:gitleaks/gitleaks" = "latest" +# workflow and YAML lint, invoked from `just dev_lint` +actionlint = "latest" +yamllint = "latest" "jq" = "latest" "mprocs" = "latest" "fd" = "latest" diff --git a/.config/mise/locks/mise.dev/yamllint/1.38.0/pyproject.toml b/.config/mise/locks/mise.dev/yamllint/1.38.0/pyproject.toml new file mode 100644 index 00000000..d94e2c24 --- /dev/null +++ b/.config/mise/locks/mise.dev/yamllint/1.38.0/pyproject.toml @@ -0,0 +1,5 @@ +[project] +name = "mise-pypi-tool-environment" +version = "0.0.0" +requires-python = ">=3.10" +dependencies = ["yamllint==1.38.0"] diff --git a/.config/mise/locks/mise.dev/yamllint/1.38.0/uv.lock b/.config/mise/locks/mise.dev/yamllint/1.38.0/uv.lock new file mode 100644 index 00000000..fec4005c --- /dev/null +++ b/.config/mise/locks/mise.dev/yamllint/1.38.0/uv.lock @@ -0,0 +1,103 @@ +version = 1 +revision = 3 +requires-python = ">=3.10" + +[options] +exclude-newer = "2026-09-12T17:50:16.853039299Z" + +[[package]] +name = "mise-pypi-tool-environment" +version = "0.0.0" +source = { virtual = "." } +dependencies = [ + { name = "yamllint" }, +] + +[package.metadata] +requires-dist = [{ name = "yamllint", specifier = "==1.38.0" }] + +[[package]] +name = "pathspec" +version = "1.1.1" +source = { registry = "https://pypi.org/simple/" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple/" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload-time = "2025-09-25T21:31:46.04Z" }, + { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload-time = "2025-09-25T21:31:47.706Z" }, + { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload-time = "2025-09-25T21:31:49.21Z" }, + { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload-time = "2025-09-25T21:31:50.735Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload-time = "2025-09-25T21:31:51.828Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload-time = "2025-09-25T21:31:53.282Z" }, + { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload-time = "2025-09-25T21:31:54.807Z" }, + { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload-time = "2025-09-25T21:31:55.885Z" }, + { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload-time = "2025-09-25T21:31:57.406Z" }, + { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, + { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, + { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, + { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, + { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, + { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, +] + +[[package]] +name = "yamllint" +version = "1.38.0" +source = { registry = "https://pypi.org/simple/" } +dependencies = [ + { name = "pathspec" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/a0/8fc2d68e132cf918f18273fdc8a1b8432b60d75ac12fdae4b0ef5c9d2e8d/yamllint-1.38.0.tar.gz", hash = "sha256:09e5f29531daab93366bb061e76019d5e91691ef0a40328f04c927387d1d364d", size = 142446, upload-time = "2026-01-13T07:47:53.276Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/92/aed08e68de6e6a3d7c2328ce7388072cd6affc26e2917197430b646aed02/yamllint-1.38.0-py3-none-any.whl", hash = "sha256:fc394a5b3be980a4062607b8fdddc0843f4fa394152b6da21722f5d59013c220", size = 68940, upload-time = "2026-01-13T07:47:51.343Z" }, +] diff --git a/.github/actionlint-matcher.json b/.github/actionlint-matcher.json new file mode 100644 index 00000000..4613e161 --- /dev/null +++ b/.github/actionlint-matcher.json @@ -0,0 +1,17 @@ +{ + "problemMatcher": [ + { + "owner": "actionlint", + "pattern": [ + { + "regexp": "^(?:\\x1b\\[\\d+m)?(.+?)(?:\\x1b\\[\\d+m)*:(?:\\x1b\\[\\d+m)*(\\d+)(?:\\x1b\\[\\d+m)*:(?:\\x1b\\[\\d+m)*(\\d+)(?:\\x1b\\[\\d+m)*: (?:\\x1b\\[\\d+m)*(.+?)(?:\\x1b\\[\\d+m)* \\[(.+?)\\]$", + "file": 1, + "line": 2, + "column": 3, + "message": 4, + "code": 5 + } + ] + } + ] +} diff --git a/.github/actionlint.yml b/.github/actionlint.yml new file mode 100644 index 00000000..30bd1077 --- /dev/null +++ b/.github/actionlint.yml @@ -0,0 +1,6 @@ +# https://github.com/rhysd/actionlint/blob/main/docs/config.md +paths: + .github/workflows/build_and_publish.yml: + # The deploy job is kept in-tree and forced off (`if: false`) until the railpack switch. + ignore: + - 'constant expression "false" in condition' diff --git a/.yamllint.yml b/.yamllint.yml new file mode 100644 index 00000000..760c4ad8 --- /dev/null +++ b/.yamllint.yml @@ -0,0 +1,27 @@ +# https://yamllint.readthedocs.io/en/stable/configuration.html +extends: default + +ignore: | + web/pnpm-lock.yaml + lefthook-local.yml + node_modules/ + .venv/ + tmp/ + +rules: + # `{ key: value }` is the flow style used in workflows. + braces: + max-spaces-inside: 1 + # `#cloud-config` must be the first bytes of cloud-init user data, with no space after `#`. + comments: + ignore: | + infra/azure/cloud-init-data-disk.yaml + # Commented-out keys (see `.commitlintrc.yml`) do not share an indentation with a live node. + comments-indentation: disable + # Files do not start with `---`. Cloud-init also requires `#cloud-config` on line 1. + document-start: disable + # Comments, shell one-liners, and copier templates are routinely past 80 columns. + line-length: disable + # GitHub Actions uses `on:` as a mapping key. + truthy: + check-keys: false diff --git a/just/dev.just b/just/dev.just index 6448b179..174faa9c 100644 --- a/just/dev.just +++ b/just/dev.just @@ -12,13 +12,35 @@ GENERATED_HOST_ENV := "env/host.sh" # we don't guard against _dev_only since this needs to be run to bootstrap the application dev_generate: _not_production dev_generate_hosts dev_generate_localias +# lint repo-level config: secrets, YAML, and GitHub Actions workflows +[script] dev_lint: + # NOTE this is important: we want all operations to run instead of fail fast + set +e + # `--log-level=debug` for debugging # will report 0 commits scanned since it just outputs a massive diff and doesn't scan commits - GIT_CONFIG_GLOBAL=/dev/null gitleaks git --report-path=- --report-format json --redact=20 --no-banner + GIT_CONFIG_GLOBAL=/dev/null gitleaks git --report-path=- --report-format json --redact=20 --no-banner || exit_code=$? # TODO link justfiles too # GIT_CONFIG_GLOBAL=/dev/null gitleaks git --report-format json --report-path - | jq -r '.[].Fingerprint' | sort -t ':' -k2 > .gitleaksignore + # yamllint's default `auto` format emits GitHub annotations when Actions sets + # GITHUB_ACTIONS and GITHUB_WORKFLOW. + yamllint --strict . || exit_code=$? + + # shellcheck and pyflakes are optional actionlint integrations. GitHub-hosted runners ship shellcheck + # and this toolchain does not, so disable both and keep local and CI results the same. + # Matcher source: https://github.com/rhysd/actionlint/blob/v1.7.12/.github/actionlint-matcher.json + if [ -n "${GITHUB_ACTIONS:-}" ]; then + echo "::add-matcher::.github/actionlint-matcher.json" + fi + actionlint -shellcheck= -pyflakes= || exit_code=$? + + if [[ -n "${exit_code:-}" ]]; then + echo "One or more commands failed" + exit 1 + fi + # start all of the services you need for development in a single terminal [script] [arg("open", long, help="open the development site in the browser", flag)] diff --git a/lefthook.yml b/lefthook.yml index 4a9626b7..3c068f85 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -45,6 +45,8 @@ pre-push: run: just py_lint js_lint: run: just js_lint + dev_lint: + run: just dev_lint # post-merge: fires after git merge / git pull # post-rewrite: fires after git rebase / git commit --amend From 88b731f5b068f3502818b25fc69596535fc00ed0 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 5 Oct 2026 14:22:14 +0000 Subject: [PATCH 2/6] chore: load yamllint config with -c Move the config to .config/yamllint.yml and pass it explicitly so it does not have to live at the repo root. Co-authored-by: Michael Bianco --- .yamllint.yml => .config/yamllint.yml | 0 just/dev.just | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename .yamllint.yml => .config/yamllint.yml (100%) diff --git a/.yamllint.yml b/.config/yamllint.yml similarity index 100% rename from .yamllint.yml rename to .config/yamllint.yml diff --git a/just/dev.just b/just/dev.just index 174faa9c..418739c3 100644 --- a/just/dev.just +++ b/just/dev.just @@ -26,7 +26,7 @@ dev_lint: # yamllint's default `auto` format emits GitHub annotations when Actions sets # GITHUB_ACTIONS and GITHUB_WORKFLOW. - yamllint --strict . || exit_code=$? + yamllint --strict -c .config/yamllint.yml . || exit_code=$? # shellcheck and pyflakes are optional actionlint integrations. GitHub-hosted runners ship shellcheck # and this toolchain does not, so disable both and keep local and CI results the same. From a26157db362f2988a68f0cf278e9440df12d149f Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 5 Oct 2026 14:26:23 +0000 Subject: [PATCH 3/6] chore: load actionlint config from .config Move the workflow lint config next to yamllint and pass it with -config-file. Co-authored-by: Michael Bianco --- {.github => .config}/actionlint.yml | 0 just/dev.just | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename {.github => .config}/actionlint.yml (100%) diff --git a/.github/actionlint.yml b/.config/actionlint.yml similarity index 100% rename from .github/actionlint.yml rename to .config/actionlint.yml diff --git a/just/dev.just b/just/dev.just index 418739c3..cdc7ce0a 100644 --- a/just/dev.just +++ b/just/dev.just @@ -34,7 +34,7 @@ dev_lint: if [ -n "${GITHUB_ACTIONS:-}" ]; then echo "::add-matcher::.github/actionlint-matcher.json" fi - actionlint -shellcheck= -pyflakes= || exit_code=$? + actionlint -config-file .config/actionlint.yml -shellcheck= -pyflakes= || exit_code=$? if [[ -n "${exit_code:-}" ]]; then echo "One or more commands failed" From 81e73698cdb329a546bb6554d02f105bfcf55cc5 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 5 Oct 2026 14:41:35 +0000 Subject: [PATCH 4/6] chore: move lefthook and commitlint configs into .config Lefthook discovers .config/lefthook.yml on its own. commitlint-rs does not, so the hook passes --config. Co-authored-by: Michael Bianco --- .commitlintrc.yml => .config/commitlintrc.yml | 0 lefthook.yml => .config/lefthook.yml | 4 +++- .config/yamllint.yml | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) rename .commitlintrc.yml => .config/commitlintrc.yml (100%) rename lefthook.yml => .config/lefthook.yml (91%) diff --git a/.commitlintrc.yml b/.config/commitlintrc.yml similarity index 100% rename from .commitlintrc.yml rename to .config/commitlintrc.yml diff --git a/lefthook.yml b/.config/lefthook.yml similarity index 91% rename from lefthook.yml rename to .config/lefthook.yml index 3c068f85..ffa28e67 100644 --- a/lefthook.yml +++ b/.config/lefthook.yml @@ -29,7 +29,9 @@ prepare-commit-msg: commit-msg: commands: commitlint: - run: commitlint + # commitlint-rs only auto-discovers a config in the working directory, so pass the path. + # The long flag is --config. The short flag in current commitlint-rs is -g, not -c. + run: commitlint --config .config/commitlintrc.yml skip: # only run this if the tool exists, it's conditionally installed # https://keisukeyamashita.github.io/commitlint-rs/ diff --git a/.config/yamllint.yml b/.config/yamllint.yml index 760c4ad8..c66cd88d 100644 --- a/.config/yamllint.yml +++ b/.config/yamllint.yml @@ -16,7 +16,7 @@ rules: comments: ignore: | infra/azure/cloud-init-data-disk.yaml - # Commented-out keys (see `.commitlintrc.yml`) do not share an indentation with a live node. + # Commented-out keys (see `.config/commitlintrc.yml`) do not share an indentation with a live node. comments-indentation: disable # Files do not start with `---`. Cloud-init also requires `#cloud-config` on line 1. document-start: disable From 284e4e33683f913f4ad50102b3ce741c647f38ed Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 5 Oct 2026 15:29:03 +0000 Subject: [PATCH 5/6] chore: keep lint configs in .config/lint Pass yamllint, actionlint, and commitlint their config paths with long flags. Lefthook has no config flag, so LEFTHOOK_CONFIG points at .config/lint/lefthook.yml. Ignore that directory in Docker and drop the old root config patterns. Co-authored-by: Michael Bianco --- .config/{ => lint}/actionlint.yml | 0 .config/{ => lint}/commitlintrc.yml | 0 .config/{ => lint}/lefthook.yml | 6 +++--- .config/{ => lint}/yamllint.yml | 2 +- .dockerignore | 5 +++-- env/dev.sh | 3 +++ just/dev.just | 4 ++-- just/setup.just | 2 +- 8 files changed, 13 insertions(+), 9 deletions(-) rename .config/{ => lint}/actionlint.yml (100%) rename .config/{ => lint}/commitlintrc.yml (100%) rename .config/{ => lint}/lefthook.yml (93%) rename .config/{ => lint}/yamllint.yml (87%) diff --git a/.config/actionlint.yml b/.config/lint/actionlint.yml similarity index 100% rename from .config/actionlint.yml rename to .config/lint/actionlint.yml diff --git a/.config/commitlintrc.yml b/.config/lint/commitlintrc.yml similarity index 100% rename from .config/commitlintrc.yml rename to .config/lint/commitlintrc.yml diff --git a/.config/lefthook.yml b/.config/lint/lefthook.yml similarity index 93% rename from .config/lefthook.yml rename to .config/lint/lefthook.yml index ffa28e67..dcda4a31 100644 --- a/.config/lefthook.yml +++ b/.config/lint/lefthook.yml @@ -1,5 +1,6 @@ # https://lefthook.dev/configuration/ # Full list of hooks: https://git-scm.com/docs/githooks +# Lefthook does not look in this directory. env/dev.sh sets LEFTHOOK_CONFIG to this file. # debug hooks with: # LEFTHOOK_VERBOSE=1 lefthook run pre-push --force @@ -29,9 +30,8 @@ prepare-commit-msg: commit-msg: commands: commitlint: - # commitlint-rs only auto-discovers a config in the working directory, so pass the path. - # The long flag is --config. The short flag in current commitlint-rs is -g, not -c. - run: commitlint --config .config/commitlintrc.yml + # commitlint-rs only auto-discovers a config in the working directory. + run: commitlint --config .config/lint/commitlintrc.yml skip: # only run this if the tool exists, it's conditionally installed # https://keisukeyamashita.github.io/commitlint-rs/ diff --git a/.config/yamllint.yml b/.config/lint/yamllint.yml similarity index 87% rename from .config/yamllint.yml rename to .config/lint/yamllint.yml index c66cd88d..7028accd 100644 --- a/.config/yamllint.yml +++ b/.config/lint/yamllint.yml @@ -16,7 +16,7 @@ rules: comments: ignore: | infra/azure/cloud-init-data-disk.yaml - # Commented-out keys (see `.config/commitlintrc.yml`) do not share an indentation with a live node. + # Commented-out keys (see `.config/lint/commitlintrc.yml`) do not share an indentation with a live node. comments-indentation: disable # Files do not start with `---`. Cloud-init also requires `#cloud-config` on line 1. document-start: disable diff --git a/.dockerignore b/.dockerignore index 9f7ad8ba..2b9e792a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -18,8 +18,7 @@ railpack.json env/ *.log docker-compose*.yml -lefthook*yml -.commitlintrc.yml +lefthook-local.yml .copier-answers.yml /copier.yml /.copier @@ -48,6 +47,8 @@ Justfile # ast-grep is dev/CI only sgconfig.yml .config/ast-grep +# YAML, workflow, commit, and git hook lint configs are dev/CI only +.config/lint # NOTE /Procfile is intentionally included, it can be used by some deployments (dokku) ################################ diff --git a/env/dev.sh b/env/dev.sh index 6dba9096..678edc28 100644 --- a/env/dev.sh +++ b/env/dev.sh @@ -1,2 +1,5 @@ export PYTHON_ENV=development export NODE_ENV=development + +# Lefthook only auto-discovers `.config/lefthook.yml`. Point it at the lint config. +export LEFTHOOK_CONFIG=$ROOT_DIR/.config/lint/lefthook.yml diff --git a/just/dev.just b/just/dev.just index cdc7ce0a..62efec64 100644 --- a/just/dev.just +++ b/just/dev.just @@ -26,7 +26,7 @@ dev_lint: # yamllint's default `auto` format emits GitHub annotations when Actions sets # GITHUB_ACTIONS and GITHUB_WORKFLOW. - yamllint --strict -c .config/yamllint.yml . || exit_code=$? + yamllint --strict --config-file .config/lint/yamllint.yml . || exit_code=$? # shellcheck and pyflakes are optional actionlint integrations. GitHub-hosted runners ship shellcheck # and this toolchain does not, so disable both and keep local and CI results the same. @@ -34,7 +34,7 @@ dev_lint: if [ -n "${GITHUB_ACTIONS:-}" ]; then echo "::add-matcher::.github/actionlint-matcher.json" fi - actionlint -config-file .config/actionlint.yml -shellcheck= -pyflakes= || exit_code=$? + actionlint --config-file .config/lint/actionlint.yml -shellcheck= -pyflakes= || exit_code=$? if [[ -n "${exit_code:-}" ]]; then echo "One or more commands failed" diff --git a/just/setup.just b/just/setup.just index ae710488..f27fba2c 100644 --- a/just/setup.just +++ b/just/setup.just @@ -29,7 +29,7 @@ requirements *flags: _dev_only rm .git/hooks/*.sample || true; \ \ echo "Installing git hooks..."; \ - lefthook install; \ + LEFTHOOK_CONFIG=.config/lint/lefthook.yml lefthook install; \ fi # setup everything required for local development From c4845da9dbf60a70da5fbaab243cb9c51dd0eeca Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 5 Oct 2026 17:18:27 +0000 Subject: [PATCH 6/6] chore: set LEFTHOOK_CONFIG from the git hook Drop the dev shell export. lefthook install still receives the path so it can write hooks that source .config/lint/lefthookrc before lefthook run. Co-authored-by: Michael Bianco --- .config/lint/lefthook.yml | 4 +++- .config/lint/lefthookrc | 3 +++ env/dev.sh | 3 --- 3 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 .config/lint/lefthookrc diff --git a/.config/lint/lefthook.yml b/.config/lint/lefthook.yml index dcda4a31..61ba9bde 100644 --- a/.config/lint/lefthook.yml +++ b/.config/lint/lefthook.yml @@ -1,6 +1,8 @@ # https://lefthook.dev/configuration/ # Full list of hooks: https://git-scm.com/docs/githooks -# Lefthook does not look in this directory. env/dev.sh sets LEFTHOOK_CONFIG to this file. +# Lefthook does not look in this directory. `lefthook install` reads this file via +# LEFTHOOK_CONFIG, then writes git hooks that source `rc` before every `lefthook run`. +rc: .config/lint/lefthookrc # debug hooks with: # LEFTHOOK_VERBOSE=1 lefthook run pre-push --force diff --git a/.config/lint/lefthookrc b/.config/lint/lefthookrc new file mode 100644 index 00000000..2d89d9b1 --- /dev/null +++ b/.config/lint/lefthookrc @@ -0,0 +1,3 @@ +# Sourced by the git hooks created with `lefthook install`. +root=$(git rev-parse --show-toplevel) +export LEFTHOOK_CONFIG="$root/.config/lint/lefthook.yml" diff --git a/env/dev.sh b/env/dev.sh index 678edc28..6dba9096 100644 --- a/env/dev.sh +++ b/env/dev.sh @@ -1,5 +1,2 @@ export PYTHON_ENV=development export NODE_ENV=development - -# Lefthook only auto-discovers `.config/lefthook.yml`. Point it at the lint config. -export LEFTHOOK_CONFIG=$ROOT_DIR/.config/lint/lefthook.yml