From 4bb845b5220b0b9bd1c575c880182776537d9b14 Mon Sep 17 00:00:00 2001 From: Benjamin Smidt Date: Tue, 14 Apr 2026 16:41:41 -0700 Subject: [PATCH 1/5] chore(lint): add surface linter config files Adds yamllint, shellcheck, and actionlint configs so the .github repo can lint itself and serve as a reference for consumer repos. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/actionlint.yml | 4 ++++ .shellcheckrc | 2 ++ .yamllint.yml | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+) create mode 100644 .github/actionlint.yml create mode 100644 .shellcheckrc create mode 100644 .yamllint.yml diff --git a/.github/actionlint.yml b/.github/actionlint.yml new file mode 100644 index 0000000..2e9302b --- /dev/null +++ b/.github/actionlint.yml @@ -0,0 +1,4 @@ +# See: https://github.com/rhysd/actionlint/blob/main/docs/config.md +self-hosted-runner: + labels: + - ubuntu-latest-m diff --git a/.shellcheckrc b/.shellcheckrc new file mode 100644 index 0000000..1e2ab45 --- /dev/null +++ b/.shellcheckrc @@ -0,0 +1,2 @@ +# Default shell dialect for scripts without a shebang. +shell=sh diff --git a/.yamllint.yml b/.yamllint.yml new file mode 100644 index 0000000..e839a57 --- /dev/null +++ b/.yamllint.yml @@ -0,0 +1,18 @@ +# See: https://yamllint.readthedocs.io/en/stable/ + +extends: default + +rules: + document-start: + present: false + line-length: + level: warning + allow-non-breakable-inline-mappings: true + # GitHub Actions uses `on:` as a workflow trigger key; YAML 1.1 treats `on` + # as a truthy boolean alias. Disable key checking to avoid false positives. + truthy: + check-keys: false + # SHA-pinned action comments use a single space before `#`. Reduce the + # minimum from the default 2 to 1 to match the existing convention. + comments: + min-spaces-from-content: 1 From 19c8030df7ae85026013da383db76e8977920bda Mon Sep 17 00:00:00 2001 From: Benjamin Smidt Date: Tue, 14 Apr 2026 16:41:53 -0700 Subject: [PATCH 2/5] feat(ci): add reusable surface-lint workflow Callable via workflow_call from any org repo. Runs yamllint, shellcheck, and actionlint with SHA-pinned actions. Accepts optional inputs for runner label, yamllint paths, and shellcheck scan directory. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/surface-lint.yml | 45 ++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 .github/workflows/surface-lint.yml diff --git a/.github/workflows/surface-lint.yml b/.github/workflows/surface-lint.yml new file mode 100644 index 0000000..6aeb781 --- /dev/null +++ b/.github/workflows/surface-lint.yml @@ -0,0 +1,45 @@ +name: Surface Lint + +on: + workflow_call: + inputs: + runs-on: + description: "Runner label" + type: string + default: "ubuntu-latest" + yamllint-file-or-dir: + description: "Path for yamllint to scan" + type: string + default: "." + yamllint-config-file: + description: "Path to yamllint config" + type: string + default: ".yamllint.yml" + shellcheck-scandir: + description: "Directory for shellcheck to scan" + type: string + default: "./scripts" + +jobs: + surface-lint: + timeout-minutes: 10 + name: surface-lint + runs-on: ${{ inputs.runs-on }} + steps: + - name: Checkout Code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + # yamllint disable rule:line-length + - name: Lint YAML + uses: ibiqlik/action-yamllint@2576378a8e339169678f9939646ee3ee325e845c # v3.1.1 + with: + file_or_dir: ${{ inputs.yamllint-file-or-dir }} + config_file: ${{ inputs.yamllint-config-file }} + + - name: Lint Shell Scripts + uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # 2.0.0 + with: + scandir: ${{ inputs.shellcheck-scandir }} + + - name: Lint GitHub Actions Workflows + uses: rhysd/actionlint@914e7df21a07ef503a81201c76d2b11c789d3fca # v1.7.12 From 150c0ec1ee06b2874feef9d52a221ad8fee4603d Mon Sep 17 00:00:00 2001 From: Benjamin Smidt Date: Tue, 14 Apr 2026 16:41:58 -0700 Subject: [PATCH 3/5] ci: add self-linting CI workflow Calls the reusable surface-lint workflow on itself to dogfood the linting setup. Shellcheck no-ops cleanly since the repo has no scripts. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/ci.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..7f30091 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,11 @@ +name: CI + +on: + pull_request: + branches: [main] + push: + branches: [main] + +jobs: + surface-lint: + uses: ./.github/workflows/surface-lint.yml From a41796bca34f1da868407daaa8fa39b3354755a1 Mon Sep 17 00:00:00 2001 From: Benjamin Smidt Date: Tue, 14 Apr 2026 16:51:02 -0700 Subject: [PATCH 4/5] refactor(ci): replace scan-path inputs with ignore inputs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove yamllint-file-or-dir, yamllint-config-file, and shellcheck-scandir inputs. Yamllint always scans "." and shellcheck always scans "./scripts". Add yamllint-ignore and shellcheck-ignore inputs for callers that need to exclude specific directories. Switch yamllint from the ibiqlik action to a run step with find+xargs since yamllint has no CLI ignore support — bash arrays handle the exclude patterns cleanly. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/surface-lint.yml | 36 +++++++++++++++++------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/.github/workflows/surface-lint.yml b/.github/workflows/surface-lint.yml index 6aeb781..036832a 100644 --- a/.github/workflows/surface-lint.yml +++ b/.github/workflows/surface-lint.yml @@ -7,18 +7,14 @@ on: description: "Runner label" type: string default: "ubuntu-latest" - yamllint-file-or-dir: - description: "Path for yamllint to scan" + yamllint-ignore: + description: "Space-separated directories to exclude from YAML linting" type: string - default: "." - yamllint-config-file: - description: "Path to yamllint config" + default: "" + shellcheck-ignore: + description: "Space-separated paths to exclude from shell script linting" type: string - default: ".yamllint.yml" - shellcheck-scandir: - description: "Directory for shellcheck to scan" - type: string - default: "./scripts" + default: "" jobs: surface-lint: @@ -29,17 +25,25 @@ jobs: - name: Checkout Code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - # yamllint disable rule:line-length - name: Lint YAML - uses: ibiqlik/action-yamllint@2576378a8e339169678f9939646ee3ee325e845c # v3.1.1 - with: - file_or_dir: ${{ inputs.yamllint-file-or-dir }} - config_file: ${{ inputs.yamllint-config-file }} + shell: bash + run: | + pip install --quiet yamllint + exclude=(-not -path './.git/*') + for dir in $YAMLLINT_IGNORE; do + exclude+=(-not -path "./$dir" -not -path "./$dir/*") + done + find . -type f \( -name '*.yml' -o -name '*.yaml' \) "${exclude[@]}" -print0 | \ + xargs -0 --no-run-if-empty yamllint -c .yamllint.yml + env: + YAMLLINT_IGNORE: ${{ inputs.yamllint-ignore }} - name: Lint Shell Scripts + # yamllint disable rule:line-length uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # 2.0.0 with: - scandir: ${{ inputs.shellcheck-scandir }} + scandir: ./scripts + ignore_paths: ${{ inputs.shellcheck-ignore }} - name: Lint GitHub Actions Workflows uses: rhysd/actionlint@914e7df21a07ef503a81201c76d2b11c789d3fca # v1.7.12 From 133a8b4cc742ff5deb0472df25673068ef85208b Mon Sep 17 00:00:00 2001 From: Benjamin Smidt Date: Tue, 14 Apr 2026 18:05:51 -0700 Subject: [PATCH 5/5] refactor(ci): remove yamllint-ignore input, restore yamllint action Yamllint ignores belong in each repo's .yamllint.yml config (the tool's native ignore: directive), not in workflow inputs. Remove the yamllint-ignore input and the find+xargs shell implementation, restore the ibiqlik/action-yamllint action with file_or_dir hardcoded to ".". Only shellcheck-ignore remains as a workflow input since shellcheck's config format has no path-exclusion mechanism. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/surface-lint.yml | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/.github/workflows/surface-lint.yml b/.github/workflows/surface-lint.yml index 036832a..a7ae9d9 100644 --- a/.github/workflows/surface-lint.yml +++ b/.github/workflows/surface-lint.yml @@ -7,10 +7,6 @@ on: description: "Runner label" type: string default: "ubuntu-latest" - yamllint-ignore: - description: "Space-separated directories to exclude from YAML linting" - type: string - default: "" shellcheck-ignore: description: "Space-separated paths to exclude from shell script linting" type: string @@ -25,18 +21,12 @@ jobs: - name: Checkout Code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + # yamllint disable rule:line-length - name: Lint YAML - shell: bash - run: | - pip install --quiet yamllint - exclude=(-not -path './.git/*') - for dir in $YAMLLINT_IGNORE; do - exclude+=(-not -path "./$dir" -not -path "./$dir/*") - done - find . -type f \( -name '*.yml' -o -name '*.yaml' \) "${exclude[@]}" -print0 | \ - xargs -0 --no-run-if-empty yamllint -c .yamllint.yml - env: - YAMLLINT_IGNORE: ${{ inputs.yamllint-ignore }} + uses: ibiqlik/action-yamllint@2576378a8e339169678f9939646ee3ee325e845c # v3.1.1 + with: + file_or_dir: . + config_file: .yamllint.yml - name: Lint Shell Scripts # yamllint disable rule:line-length