From 50aaff90a83fcd2ad01945e109722e08ae05e4f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Nov 2025 18:51:44 +0000 Subject: [PATCH 01/10] Bump the go-dependencies group across 1 directory with 8 updates Bumps the go-dependencies group with 6 updates in the / directory: | Package | From | To | | --- | --- | --- | | [github.com/cli/go-gh/v2](https://github.com/cli/go-gh) | `2.12.2` | `2.13.0` | | [github.com/spf13/cobra](https://github.com/spf13/cobra) | `1.9.1` | `1.10.1` | | [github.com/lucasb-eyer/go-colorful](https://github.com/lucasb-eyer/go-colorful) | `1.2.0` | `1.3.0` | | [golang.org/x/image](https://github.com/golang/image) | `0.30.0` | `0.32.0` | | [golang.org/x/sys](https://github.com/golang/sys) | `0.35.0` | `0.38.0` | | [golang.org/x/term](https://github.com/golang/term) | `0.34.0` | `0.36.0` | Updates `github.com/cli/go-gh/v2` from 2.12.2 to 2.13.0 - [Release notes](https://github.com/cli/go-gh/releases) - [Commits](https://github.com/cli/go-gh/compare/v2.12.2...v2.13.0) Updates `github.com/spf13/cobra` from 1.9.1 to 1.10.1 - [Release notes](https://github.com/spf13/cobra/releases) - [Commits](https://github.com/spf13/cobra/compare/v1.9.1...v1.10.1) Updates `github.com/lucasb-eyer/go-colorful` from 1.2.0 to 1.3.0 - [Release notes](https://github.com/lucasb-eyer/go-colorful/releases) - [Changelog](https://github.com/lucasb-eyer/go-colorful/blob/master/CHANGELOG.md) - [Commits](https://github.com/lucasb-eyer/go-colorful/compare/v1.2.0...v1.3.0) Updates `github.com/spf13/pflag` from 1.0.7 to 1.0.9 - [Release notes](https://github.com/spf13/pflag/releases) - [Commits](https://github.com/spf13/pflag/compare/v1.0.7...v1.0.9) Updates `golang.org/x/image` from 0.30.0 to 0.32.0 - [Commits](https://github.com/golang/image/compare/v0.30.0...v0.32.0) Updates `golang.org/x/sys` from 0.35.0 to 0.38.0 - [Commits](https://github.com/golang/sys/compare/v0.35.0...v0.38.0) Updates `golang.org/x/term` from 0.34.0 to 0.36.0 - [Commits](https://github.com/golang/term/compare/v0.34.0...v0.36.0) Updates `golang.org/x/text` from 0.28.0 to 0.30.0 - [Release notes](https://github.com/golang/text/releases) - [Commits](https://github.com/golang/text/compare/v0.28.0...v0.30.0) --- updated-dependencies: - dependency-name: github.com/cli/go-gh/v2 dependency-version: 2.13.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-dependencies - dependency-name: github.com/spf13/cobra dependency-version: 1.10.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-dependencies - dependency-name: github.com/lucasb-eyer/go-colorful dependency-version: 1.3.0 dependency-type: indirect update-type: version-update:semver-minor dependency-group: go-dependencies - dependency-name: github.com/spf13/pflag dependency-version: 1.0.9 dependency-type: indirect update-type: version-update:semver-patch dependency-group: go-dependencies - dependency-name: golang.org/x/image dependency-version: 0.32.0 dependency-type: indirect update-type: version-update:semver-minor dependency-group: go-dependencies - dependency-name: golang.org/x/sys dependency-version: 0.38.0 dependency-type: indirect update-type: version-update:semver-minor dependency-group: go-dependencies - dependency-name: golang.org/x/term dependency-version: 0.36.0 dependency-type: indirect update-type: version-update:semver-minor dependency-group: go-dependencies - dependency-name: golang.org/x/text dependency-version: 0.30.0 dependency-type: indirect update-type: version-update:semver-minor dependency-group: go-dependencies ... Signed-off-by: dependabot[bot] --- go.mod | 18 +++++++++--------- go.sum | 37 ++++++++++++++++++------------------- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/go.mod b/go.mod index f5bff99..8b5b340 100644 --- a/go.mod +++ b/go.mod @@ -1,11 +1,11 @@ module github.com/github/gh-skyline -go 1.24.1 +go 1.25.0 require ( - github.com/cli/go-gh/v2 v2.12.2 + github.com/cli/go-gh/v2 v2.13.0 github.com/fogleman/gg v1.3.0 - github.com/spf13/cobra v1.9.1 + github.com/spf13/cobra v1.10.1 ) require ( @@ -18,15 +18,15 @@ require ( github.com/henvic/httpretty v0.1.4 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/kr/pretty v0.3.1 // indirect - github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/lucasb-eyer/go-colorful v1.3.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/muesli/termenv v0.16.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect - github.com/spf13/pflag v1.0.7 // indirect + github.com/spf13/pflag v1.0.9 // indirect github.com/thlib/go-timezone-local v0.0.7 // indirect - golang.org/x/image v0.30.0 // indirect - golang.org/x/sys v0.35.0 // indirect - golang.org/x/term v0.34.0 // indirect - golang.org/x/text v0.28.0 // indirect + golang.org/x/image v0.32.0 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/term v0.36.0 // indirect + golang.org/x/text v0.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index e091470..26e473e 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiE github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/cli/browser v1.3.0 h1:LejqCrpWr+1pRqmEPDGnTZOjsMe7sehifLynZJuqJpo= github.com/cli/browser v1.3.0/go.mod h1:HH8s+fOAxjhQoBUAsKuPCbqUuxZDhQ2/aD+SzsEfBTk= -github.com/cli/go-gh/v2 v2.12.2 h1:EtocmDAH7dKrH2PscQOQVo7PbFD5G6uYx4rSKY2w1SY= -github.com/cli/go-gh/v2 v2.12.2/go.mod h1:g2IjwHEo27fgItlS9wUbRaXPYurZEXPp1jrxf3piC6g= +github.com/cli/go-gh/v2 v2.13.0 h1:jEHZu/VPVoIJkciK3pzZd3rbT8J90swsK5Ui4ewH1ys= +github.com/cli/go-gh/v2 v2.13.0/go.mod h1:Us/NbQ8VNM0fdaILgoXSz6PKkV5PWaEzkJdc9vR2geM= github.com/cli/safeexec v1.0.1 h1:e/C79PbXF4yYTN/wauC4tviMxEV13BwljGj0N9j+N00= github.com/cli/safeexec v1.0.1/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q= github.com/cli/shurcooL-graphql v0.0.4 h1:6MogPnQJLjKkaXPyGqPRXOI2qCsQdqNfUY1QSJu2GuY= @@ -28,8 +28,8 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= -github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag= +github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= @@ -42,27 +42,26 @@ github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= -github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= -github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= +github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= +github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/thlib/go-timezone-local v0.0.7 h1:fX8zd3aJydqLlTs/TrROrIIdztzsdFV23OzOQx31jII= github.com/thlib/go-timezone-local v0.0.7/go.mod h1:/Tnicc6m/lsJE0irFMA0LfIwTBo4QP7A8IfyIv4zZKI= -golang.org/x/image v0.30.0 h1:jD5RhkmVAnjqaCUXfbGBrn3lpxbknfN9w2UhHHU+5B4= -golang.org/x/image v0.30.0/go.mod h1:SAEUTxCCMWSrJcCy/4HwavEsfZZJlYxeHLc6tTiAe/c= +golang.org/x/image v0.32.0 h1:6lZQWq75h7L5IWNk0r+SCpUJ6tUVd3v4ZHnbRKLkUDQ= +golang.org/x/image v0.32.0/go.mod h1:/R37rrQmKXtO6tYXAjtDLwQgFLHmhW+V6ayXlxzP2Pc= golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= -golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= -golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= -golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= -golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= -golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= -golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= +golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= +golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= +golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= +golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From f6312a9b3980920a98ac7734f75153aa21f1110d Mon Sep 17 00:00:00 2001 From: Chris Reddington <791642+chrisreddington@users.noreply.github.com> Date: Tue, 27 Jan 2026 09:00:09 +0000 Subject: [PATCH 02/10] Update Super-Linter to version 8.3.2 in linter workflow --- .github/workflows/linter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 2a52548..5322828 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -29,7 +29,7 @@ jobs: go-version-file: go.mod - name: Run Super-Linter - uses: super-linter/super-linter/slim@5119dcd8011e92182ce8219d9e9efc82f16fddb6 # v8.0.0 + uses: super-linter/super-linter/slim@d5b0a2ab116623730dd094f15ddc1b6b25bf7b99 # v8.3.2 env: VALIDATE_ALL_CODEBASE: true DEFAULT_BRANCH: "main" From 5395d75ddadd6f1dcc14804dee1866265c450468 Mon Sep 17 00:00:00 2001 From: Chris Reddington <791642+chrisreddington@users.noreply.github.com> Date: Tue, 27 Jan 2026 09:16:20 +0000 Subject: [PATCH 03/10] Refactor devcontainer and VSCode settings for improved readability and consistency --- .devcontainer/devcontainer.json | 68 ++++++++++++++++----------------- .vscode/settings.json | 28 +++++++------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index ac35121..16f9bf5 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,44 +1,44 @@ // For format details, see https://aka.ms/devcontainer.json. For config options, see the // README at: https://github.com/devcontainers/templates/tree/main/src/go { - "name": "Go", - // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile - "image": "mcr.microsoft.com/devcontainers/go:1-1.24-bookworm", - "customizations": { - "vscode": { - "extensions": [ - "GitHub.codespaces", - "github.vscode-github-actions", - "GitHub.copilot", - "GitHub.copilot-chat", - "github.copilot-workspace", - "GitHub.vscode-pull-request-github", - "GitHub.remotehub", - "golang.Go" - ] - } - }, - "tasks": { - "build": "go build .", - "test": "go test ./...", - "run": "go run ." - }, + "name": "Go", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/go:1-1.24-bookworm", + "customizations": { + "vscode": { + "extensions": [ + "GitHub.codespaces", + "github.vscode-github-actions", + "GitHub.copilot", + "GitHub.copilot-chat", + "github.copilot-workspace", + "GitHub.vscode-pull-request-github", + "GitHub.remotehub", + "golang.Go" + ] + } + }, + "tasks": { + "build": "go build .", + "test": "go test ./...", + "run": "go run ." + }, - // Features to add to the dev container. More info: https://containers.dev/features. + // Features to add to the dev container. More info: https://containers.dev/features. - "features": { - "ghcr.io/devcontainers/features/github-cli:1": {} - }, + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {} + }, - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], - // Use 'postCreateCommand' to run commands after the container is created. - "postCreateCommand": "go install -v golang.org/x/tools/cmd/goimports@latest" + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "go install -v golang.org/x/tools/cmd/goimports@latest" - // Configure tool-specific properties. - // "customizations": {}, + // Configure tool-specific properties. + // "customizations": {}, - // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. - // "remoteUser": "root" + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" } diff --git a/.vscode/settings.json b/.vscode/settings.json index ee878d0..e8702bc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,19 +1,19 @@ { - // Use golangci-lint for linting - "go.lintTool": "golangci-lint", + // Use golangci-lint for linting + "go.lintTool": "golangci-lint", - // Configure linter flags - "go.lintFlags": ["--fast"], + // Configure linter flags + "go.lintFlags": ["--fast"], - "go.formatTool": "goimports", - "go.useLanguageServer": true, - "go.testOnSave": true, + "go.formatTool": "goimports", + "go.useLanguageServer": true, + "go.testOnSave": true, - // Editor settings optimized for Go development - "[go]": { - "editor.formatOnSave": true, - "editor.codeActionsOnSave": { - "source.organizeImports": "always" - } - } + // Editor settings optimized for Go development + "[go]": { + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.organizeImports": "always" + } + } } From 42aaf2664586107ffe770b469f4b62422fafeabd Mon Sep 17 00:00:00 2001 From: Chris Reddington <791642+chrisreddington@users.noreply.github.com> Date: Tue, 27 Jan 2026 09:16:31 +0000 Subject: [PATCH 04/10] Add cooldown settings for go-dependencies and github-actions in dependabot configuration --- .github/dependabot.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 2d76a1b..8c3e8ea 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -9,6 +9,9 @@ updates: directory: "/" # Location of package manifests schedule: interval: "weekly" + cooldown: + default: 3 + semver-major: 7 allow: - dependency-type: "direct" - dependency-type: "indirect" @@ -20,6 +23,9 @@ updates: directory: "/" # Location of package manifests schedule: interval: "weekly" + cooldown: + default: 3 + semver-major: 7 groups: github-actions: patterns: From 2849ea93b9c3f01684cea571c8f8476bab5e00fc Mon Sep 17 00:00:00 2001 From: Chris Reddington <791642+chrisreddington@users.noreply.github.com> Date: Tue, 27 Jan 2026 09:20:40 +0000 Subject: [PATCH 05/10] Update GitHub Action workflows for consistency --- .../github-actions.instructions.md | 194 ++++++++++++++++++ .github/workflows/build.yml | 9 +- .github/workflows/linter.yml | 6 +- .github/workflows/release.yml | 5 +- 4 files changed, 208 insertions(+), 6 deletions(-) create mode 100644 .github/instructions/github-actions.instructions.md diff --git a/.github/instructions/github-actions.instructions.md b/.github/instructions/github-actions.instructions.md new file mode 100644 index 0000000..560b1c4 --- /dev/null +++ b/.github/instructions/github-actions.instructions.md @@ -0,0 +1,194 @@ +--- +applyTo: ".github/workflows/**/*.{yml,yaml}" +description: GitHub Actions workflow development patterns and security recommended practices +--- + +# GitHub Actions Workflow Development + +Guidelines for secure and maintainable GitHub Actions workflows. + +## Security Best Practices + +### Minimal Permissions + +```yaml +# ✅ Minimal at workflow level +permissions: + contents: read + +# Increase per-job only when needed +jobs: + deploy: + permissions: + contents: read + deployments: write +``` + +### SHA Pinning (CRITICAL) + +**Always pin third-party actions to full commit SHA and use the latest release:** + +```yaml +# ✅ Pin to commit SHA - immutable and secure +- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 +``` + +**Before submitting workflow changes:** + +1. **Find Latest Release**: Check the action's releases page (e.g., `https://github.com/actions/checkout/releases`) +2. **Get Commit SHA**: Use GitHub MCP tools or the releases page to get the full 40-character commit SHA +3. **Include Version Comment**: Always include the version tag as a trailing comment (e.g., `# v6.0.2`) + +### Credential Security + +**Always set `persist-credentials: false` on checkout actions:** + +```yaml +# ✅ Secure - credentials not persisted +- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false +``` + +This prevents credentials from being stored in the git config. + +### Script Injection Prevention + +```yaml +# ✅ Safe - environment variable +- name: Check PR title + env: + TITLE: ${{ github.event.pull_request.title }} + run: | + if [[ "$TITLE" =~ ^feat ]]; then + echo "Valid feature PR" + fi + +# ❌ Unsafe - direct interpolation +- run: | + if [[ "${{ github.event.pull_request.title }}" =~ ^feat ]]; then +``` + +### Secrets Handling + +```yaml +# ✅ Reference secrets properly +env: + API_KEY: ${{ secrets.API_KEY }} + +# Mask generated sensitive values +- run: | + TOKEN=$(generate-token) + echo "::add-mask::$TOKEN" + echo "TOKEN=$TOKEN" >> $GITHUB_ENV +``` + +## Workflow Structure + +### YAML Document Start + +Always begin workflow files with `---` for proper YAML parsing: + +```yaml +--- +name: CI +on: + push: + branches: [main] +``` + +### Environment Consistency + +**Prefer configuration files over hardcoded versions:** + +```yaml +# Go projects - use go.mod +- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 + with: + go-version-file: go.mod + +# Node.js projects - use .node-version or .nvmrc +- uses: actions/setup-node@v4 + with: + node-version-file: '.node-version' +``` + +### Conditional Execution + +```yaml +# Run only on main +- run: ./deploy.sh + if: github.ref == 'refs/heads/main' + +# Continue on error +- run: ./optional-step.sh + continue-on-error: true + +# Run even if previous failed +- run: ./cleanup.sh + if: always() +``` + +## Dependabot Configuration + +### Cooldown Settings + +Configure cooldown periods to prevent excessive PR churn: + +```yaml +version: 2 +updates: + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "weekly" + cooldown: + default: 3 + semver-major: 7 +``` + +## Verification Checklist (MANDATORY) + +Before finalizing any workflow changes: + +1. **Verify Each Action's Commit SHA:** + - Use GitHub MCP tools (`get_commit` with the tag) to retrieve the correct 40-character SHA + - **Do NOT assume** the SHA in comments or existing workflows is correct + - **Always use the latest release** - check the releases page for each action + +2. **Validate Action Existence:** + - After updating SHAs, confirm the action exists at that commit + - If the commit lookup fails or returns 404, the SHA is invalid + +3. **Security Checks:** + - Ensure `persist-credentials: false` is set on all checkout actions + - Verify minimal permissions are configured at workflow level + - Check that no secrets are directly interpolated in run commands + +4. **Test YAML Syntax:** + - Verify the workflow has valid YAML syntax + - Ensure the file starts with `---` + +## Before Making Changes + +1. Check existing `.github/workflows/` for established patterns +2. Check `.github/dependabot.yml` for dependency automation settings +3. Verify action versions via releases pages using GitHub MCP tools +4. Consider CI time and complexity tradeoffs + +## Keeping Instructions Up-to-Date + +**IMPORTANT**: When making changes to workflow files that introduce new patterns or security practices, update this instruction file to reflect those changes. + +--- + +## Anti-Patterns + +| Anti-Pattern | Why It's Problematic | Better Approach | +|--------------|---------------------|-----------------| +| Using version tags (`v4`) | Tags can be moved/deleted; supply chain risk | Pin to full 40-char commit SHA | +| Direct string interpolation | Script injection vulnerability | Use environment variables | +| Workflow-level `write` perms | Excessive access if job compromised | Minimal perms at workflow, increase per-job | +| Hardcoded language versions | Drift between local and CI | Use version files (go.mod, .node-version) | +| Assuming SHA validity | Outdated SHAs break workflows | Verify SHA against latest release | +| Missing YAML document start | Parser warnings and inconsistency | Always start with `---` | diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4a9c909..01663dd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,3 +1,4 @@ +--- # .github/workflows/build.yml name: Build @@ -15,10 +16,12 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 with: go-version-file: go.mod @@ -32,7 +35,7 @@ jobs: go tool cover -func=coverage.out > coverage.txt - name: Upload Coverage Artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: coverage-report path: | diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 5322828..20ce7e5 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -1,3 +1,4 @@ +--- name: Lint Code Base permissions: @@ -19,12 +20,13 @@ jobs: steps: - name: Checkout Code - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 + persist-credentials: false - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 with: go-version-file: go.mod diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2df551f..34e9550 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,3 +1,4 @@ +--- name: release on: push: @@ -12,7 +13,9 @@ jobs: release: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: cli/gh-extension-precompile@9e2237c30f869ad3bcaed6a4be2cd43564dd421b # v2.1.0 with: release_android: true From 93903ef191e27ae974f02ec94541a0144d73417e Mon Sep 17 00:00:00 2001 From: Chris Reddington <791642+chrisreddington@users.noreply.github.com> Date: Tue, 27 Jan 2026 09:24:07 +0000 Subject: [PATCH 06/10] Update Dependabot configuration with enhanced cooldown settings and add guidelines for usage --- .github/dependabot.yml | 14 +- .../instructions/dependabot.instructions.md | 143 ++++++++++++++++++ .../github-actions.instructions.md | 18 --- 3 files changed, 151 insertions(+), 24 deletions(-) create mode 100644 .github/instructions/dependabot.instructions.md diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 8c3e8ea..1e67f8c 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -9,9 +9,10 @@ updates: directory: "/" # Location of package manifests schedule: interval: "weekly" - cooldown: - default: 3 - semver-major: 7 + cooldown: + default: "3d" + types: + major: "7d" allow: - dependency-type: "direct" - dependency-type: "indirect" @@ -23,9 +24,10 @@ updates: directory: "/" # Location of package manifests schedule: interval: "weekly" - cooldown: - default: 3 - semver-major: 7 + cooldown: + default: "3d" + types: + major: "7d" groups: github-actions: patterns: diff --git a/.github/instructions/dependabot.instructions.md b/.github/instructions/dependabot.instructions.md new file mode 100644 index 0000000..3fe8e76 --- /dev/null +++ b/.github/instructions/dependabot.instructions.md @@ -0,0 +1,143 @@ +--- +applyTo: "**/*dependabot.yml" +description: Dependabot configuration patterns and best practices +--- + +# Dependabot Configuration + +Guidelines for configuring Dependabot version updates. + +## Basic Structure + +```yaml +version: 2 +updates: + - package-ecosystem: "gomod" # or npm, pip, docker, github-actions, etc. + directory: "/" + schedule: + interval: "weekly" # daily, weekly, or monthly +``` + +## Cooldown Settings + +Configure cooldown periods to prevent excessive PR churn. This waits for packages to mature before creating update PRs: + +```yaml +version: 2 +updates: + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "weekly" + cooldown: + default: "3d" # Wait 3 days for all updates + types: + patch: "1d" # Patch updates wait 1 day + minor: "3d" # Minor updates wait 3 days + major: "7d" # Major updates wait 7 days + exclude: + - "critical-pkg*" # Packages to exclude from cooldown +``` + +**Key options:** +- `default`: Minimum age for all updates unless overridden +- `types`: Per-semver level cooldowns (`patch`, `minor`, `major`) +- `exclude`: Package names or wildcards to skip cooldown (for urgent updates) + +**Note:** Security updates automatically bypass cooldown periods. + +## Grouping Updates + +Group related dependencies into single PRs to reduce noise: + +```yaml +updates: + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "weekly" + groups: + go-dependencies: + patterns: + - "*" # Group all Go dependencies +``` + +You can create multiple groups with specific patterns: + +```yaml +groups: + aws-sdk: + patterns: + - "github.com/aws/*" + testing: + patterns: + - "*test*" + - "*mock*" +``` + +## Filtering Dependencies + +### Allow specific dependency types + +```yaml +allow: + - dependency-type: "direct" # Only direct dependencies + - dependency-type: "indirect" # Include transitive dependencies +``` + +### Ignore specific dependencies + +```yaml +ignore: + - dependency-name: "lodash" + versions: ["4.x"] # Ignore lodash 4.x updates + - dependency-name: "aws-sdk" + update-types: ["version-update:semver-major"] # Ignore major updates +``` + +## Common Ecosystems + +| Ecosystem | `package-ecosystem` value | +|-----------|---------------------------| +| Go modules | `gomod` | +| npm/yarn | `npm` | +| Python pip | `pip` | +| Docker | `docker` | +| GitHub Actions | `github-actions` | +| Terraform | `terraform` | +| Cargo (Rust) | `cargo` | + +## Complete Example + +```yaml +version: 2 +updates: + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "weekly" + cooldown: + default: "3d" + types: + major: "7d" + allow: + - dependency-type: "direct" + - dependency-type: "indirect" + groups: + go-dependencies: + patterns: + - "*" + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + cooldown: + default: "3d" + types: + major: "7d" + groups: + github-actions: + patterns: + - "*" +``` diff --git a/.github/instructions/github-actions.instructions.md b/.github/instructions/github-actions.instructions.md index 560b1c4..b234c95 100644 --- a/.github/instructions/github-actions.instructions.md +++ b/.github/instructions/github-actions.instructions.md @@ -129,24 +129,6 @@ on: if: always() ``` -## Dependabot Configuration - -### Cooldown Settings - -Configure cooldown periods to prevent excessive PR churn: - -```yaml -version: 2 -updates: - - package-ecosystem: "gomod" - directory: "/" - schedule: - interval: "weekly" - cooldown: - default: 3 - semver-major: 7 -``` - ## Verification Checklist (MANDATORY) Before finalizing any workflow changes: From 6c082a23118b127b94ba6c781a0f3d4adda6c26c Mon Sep 17 00:00:00 2001 From: Chris Reddington <791642+chrisreddington@users.noreply.github.com> Date: Tue, 27 Jan 2026 09:27:14 +0000 Subject: [PATCH 07/10] Refactor cooldown settings in Dependabot configuration for clarity and consistency --- .github/dependabot.yml | 10 ++-- .../instructions/dependabot.instructions.md | 60 +++++++++++++------ 2 files changed, 46 insertions(+), 24 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 1e67f8c..8641fb9 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -10,9 +10,8 @@ updates: schedule: interval: "weekly" cooldown: - default: "3d" - types: - major: "7d" + default-days: 3 + semver-major-days: 7 allow: - dependency-type: "direct" - dependency-type: "indirect" @@ -25,9 +24,8 @@ updates: schedule: interval: "weekly" cooldown: - default: "3d" - types: - major: "7d" + default-days: 3 + semver-major-days: 7 groups: github-actions: patterns: diff --git a/.github/instructions/dependabot.instructions.md b/.github/instructions/dependabot.instructions.md index 3fe8e76..774381a 100644 --- a/.github/instructions/dependabot.instructions.md +++ b/.github/instructions/dependabot.instructions.md @@ -20,7 +20,7 @@ updates: ## Cooldown Settings -Configure cooldown periods to prevent excessive PR churn. This waits for packages to mature before creating update PRs: +Configure cooldown periods to delay updates until packages have matured. This helps avoid churn from rapid releases. Cooldown only applies to version updates, not security updates. ```yaml version: 2 @@ -30,21 +30,31 @@ updates: schedule: interval: "weekly" cooldown: - default: "3d" # Wait 3 days for all updates - types: - patch: "1d" # Patch updates wait 1 day - minor: "3d" # Minor updates wait 3 days - major: "7d" # Major updates wait 7 days + default-days: 3 # Default cooldown for all updates + semver-major-days: 7 # Major version updates wait 7 days + semver-minor-days: 3 # Minor version updates wait 3 days + semver-patch-days: 1 # Patch version updates wait 1 day + include: + - "some-package*" # Only apply cooldown to matching packages exclude: - - "critical-pkg*" # Packages to exclude from cooldown + - "critical-pkg*" # Skip cooldown for these packages ``` -**Key options:** -- `default`: Minimum age for all updates unless overridden -- `types`: Per-semver level cooldowns (`patch`, `minor`, `major`) -- `exclude`: Package names or wildcards to skip cooldown (for urgent updates) +**Parameters:** -**Note:** Security updates automatically bypass cooldown periods. +| Parameter | Description | +|-----------|-------------| +| `default-days` | Default cooldown period for all dependencies | +| `semver-major-days` | Cooldown for major version updates | +| `semver-minor-days` | Cooldown for minor version updates | +| `semver-patch-days` | Cooldown for patch version updates | +| `include` | List of dependencies to apply cooldown (supports wildcards) | +| `exclude` | List of dependencies excluded from cooldown (supports wildcards) | + +**Notes:** +- If semver-specific days aren't defined, `default-days` is used +- `exclude` takes precedence over `include` +- Security updates automatically bypass cooldown ## Grouping Updates @@ -73,8 +83,15 @@ groups: patterns: - "*test*" - "*mock*" + dependency-type: "development" ``` +Group parameters: +- `patterns`: Include dependencies matching these patterns +- `exclude-patterns`: Exclude dependencies matching these patterns +- `dependency-type`: Limit to `development` or `production` +- `update-types`: Limit to `minor`, `patch`, or `major` + ## Filtering Dependencies ### Allow specific dependency types @@ -83,6 +100,7 @@ groups: allow: - dependency-type: "direct" # Only direct dependencies - dependency-type: "indirect" # Include transitive dependencies + - dependency-type: "all" # All dependencies ``` ### Ignore specific dependencies @@ -106,6 +124,7 @@ ignore: | GitHub Actions | `github-actions` | | Terraform | `terraform` | | Cargo (Rust) | `cargo` | +| NuGet (.NET) | `nuget` | ## Complete Example @@ -117,9 +136,8 @@ updates: schedule: interval: "weekly" cooldown: - default: "3d" - types: - major: "7d" + default-days: 3 + semver-major-days: 7 allow: - dependency-type: "direct" - dependency-type: "indirect" @@ -133,11 +151,17 @@ updates: schedule: interval: "weekly" cooldown: - default: "3d" - types: - major: "7d" + default-days: 3 + semver-major-days: 7 groups: github-actions: patterns: - "*" ``` + +--- + +## References + +- [Dependabot Configuration Options](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file) - Full configuration reference +- [Optimizing PR Creation](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/optimizing-pr-creation-version-updates) - Cooldown and grouping strategies From b4362d7ef908c0113eb285481fef1479319ff5e2 Mon Sep 17 00:00:00 2001 From: Chris Reddington <791642+chrisreddington@users.noreply.github.com> Date: Tue, 27 Jan 2026 09:41:02 +0000 Subject: [PATCH 08/10] Update Dependabot configuration cooldown settings and several linting fixes --- .github/dependabot.yml | 5 +- .../instructions/dependabot.instructions.md | 117 +++++++++++------- .../github-actions.instructions.md | 24 ++-- internal/ascii/generator.go | 4 + internal/errors/errors_test.go | 60 ++++----- 5 files changed, 122 insertions(+), 88 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 8641fb9..d6ab863 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -10,7 +10,7 @@ updates: schedule: interval: "weekly" cooldown: - default-days: 3 + default-days: 7 semver-major-days: 7 allow: - dependency-type: "direct" @@ -24,8 +24,7 @@ updates: schedule: interval: "weekly" cooldown: - default-days: 3 - semver-major-days: 7 + default-days: 7 groups: github-actions: patterns: diff --git a/.github/instructions/dependabot.instructions.md b/.github/instructions/dependabot.instructions.md index 774381a..8655a2e 100644 --- a/.github/instructions/dependabot.instructions.md +++ b/.github/instructions/dependabot.instructions.md @@ -12,10 +12,10 @@ Guidelines for configuring Dependabot version updates. ```yaml version: 2 updates: - - package-ecosystem: "gomod" # or npm, pip, docker, github-actions, etc. + - package-ecosystem: "gomod" # or npm, pip, docker, github-actions, etc. directory: "/" schedule: - interval: "weekly" # daily, weekly, or monthly + interval: "weekly" # daily, weekly, or monthly ``` ## Cooldown Settings @@ -23,39 +23,65 @@ updates: Configure cooldown periods to delay updates until packages have matured. This helps avoid churn from rapid releases. Cooldown only applies to version updates, not security updates. ```yaml -version: 2 -updates: - - package-ecosystem: "gomod" - directory: "/" - schedule: - interval: "weekly" - cooldown: - default-days: 3 # Default cooldown for all updates - semver-major-days: 7 # Major version updates wait 7 days - semver-minor-days: 3 # Minor version updates wait 3 days - semver-patch-days: 1 # Patch version updates wait 1 day - include: - - "some-package*" # Only apply cooldown to matching packages - exclude: - - "critical-pkg*" # Skip cooldown for these packages +cooldown: + default-days: 7 # Default cooldown for all updates + semver-major-days: 7 # Major version updates wait 7 days + semver-minor-days: 3 # Minor version updates wait 3 days + semver-patch-days: 1 # Patch version updates wait 1 day + include: + - "some-package*" # Only apply cooldown to matching packages + exclude: + - "critical-pkg*" # Skip cooldown for these packages ``` **Parameters:** -| Parameter | Description | -|-----------|-------------| -| `default-days` | Default cooldown period for all dependencies | -| `semver-major-days` | Cooldown for major version updates | -| `semver-minor-days` | Cooldown for minor version updates | -| `semver-patch-days` | Cooldown for patch version updates | -| `include` | List of dependencies to apply cooldown (supports wildcards) | -| `exclude` | List of dependencies excluded from cooldown (supports wildcards) | +| Parameter | Description | +| ------------------- | ---------------------------------------------------------------- | +| `default-days` | Default cooldown period for all dependencies | +| `semver-major-days` | Cooldown for major version updates | +| `semver-minor-days` | Cooldown for minor version updates | +| `semver-patch-days` | Cooldown for patch version updates | +| `include` | List of dependencies to apply cooldown (supports wildcards) | +| `exclude` | List of dependencies excluded from cooldown (supports wildcards) | **Notes:** + - If semver-specific days aren't defined, `default-days` is used - `exclude` takes precedence over `include` - Security updates automatically bypass cooldown +### SemVer Cooldown Support by Ecosystem + +**IMPORTANT:** The `semver-major-days`, `semver-minor-days`, and `semver-patch-days` options are NOT supported by all package ecosystems. For unsupported ecosystems, use only `default-days`. + +| Ecosystem | SemVer Cooldown Supported | +| ---------------- | ------------------------------- | +| `gomod` | ✅ Yes | +| `npm` | ✅ Yes | +| `pip` | ✅ Yes | +| `bundler` | ✅ Yes | +| `cargo` | ✅ Yes | +| `composer` | ✅ Yes | +| `maven` | ✅ Yes | +| `gradle` | ✅ Yes | +| `nuget` | ✅ Yes | +| `docker` | ✅ Yes | +| `github-actions` | ❌ No - use `default-days` only | +| `gitsubmodule` | ❌ No - use `default-days` only | +| `terraform` | ❌ No - use `default-days` only | + +**Example for github-actions (no semver support):** + +```yaml +- package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + cooldown: + default-days: 7 # Only default-days is supported +``` + ## Grouping Updates Group related dependencies into single PRs to reduce noise: @@ -69,7 +95,7 @@ updates: groups: go-dependencies: patterns: - - "*" # Group all Go dependencies + - "*" # Group all Go dependencies ``` You can create multiple groups with specific patterns: @@ -87,6 +113,7 @@ groups: ``` Group parameters: + - `patterns`: Include dependencies matching these patterns - `exclude-patterns`: Exclude dependencies matching these patterns - `dependency-type`: Limit to `development` or `production` @@ -98,9 +125,9 @@ Group parameters: ```yaml allow: - - dependency-type: "direct" # Only direct dependencies - - dependency-type: "indirect" # Include transitive dependencies - - dependency-type: "all" # All dependencies + - dependency-type: "direct" # Only direct dependencies + - dependency-type: "indirect" # Include transitive dependencies + - dependency-type: "all" # All dependencies ``` ### Ignore specific dependencies @@ -108,35 +135,36 @@ allow: ```yaml ignore: - dependency-name: "lodash" - versions: ["4.x"] # Ignore lodash 4.x updates + versions: ["4.x"] # Ignore lodash 4.x updates - dependency-name: "aws-sdk" - update-types: ["version-update:semver-major"] # Ignore major updates + update-types: ["version-update:semver-major"] # Ignore major updates ``` ## Common Ecosystems -| Ecosystem | `package-ecosystem` value | -|-----------|---------------------------| -| Go modules | `gomod` | -| npm/yarn | `npm` | -| Python pip | `pip` | -| Docker | `docker` | -| GitHub Actions | `github-actions` | -| Terraform | `terraform` | -| Cargo (Rust) | `cargo` | -| NuGet (.NET) | `nuget` | +| Ecosystem | `package-ecosystem` value | +| -------------- | ------------------------- | +| Go modules | `gomod` | +| npm/Yarn | `npm` | +| Python pip | `pip` | +| Docker | `docker` | +| GitHub Actions | `github-actions` | +| Terraform | `terraform` | +| Cargo (Rust) | `cargo` | +| NuGet (.NET) | `nuget` | ## Complete Example ```yaml version: 2 updates: + # Go modules - supports semver cooldown - package-ecosystem: "gomod" directory: "/" schedule: interval: "weekly" cooldown: - default-days: 3 + default-days: 7 semver-major-days: 7 allow: - dependency-type: "direct" @@ -146,13 +174,13 @@ updates: patterns: - "*" + # GitHub Actions - does NOT support semver cooldown - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" cooldown: - default-days: 3 - semver-major-days: 7 + default-days: 7 groups: github-actions: patterns: @@ -164,4 +192,5 @@ updates: ## References - [Dependabot Configuration Options](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file) - Full configuration reference +- [Supported Ecosystems](https://docs.github.com/en/code-security/dependabot/ecosystems-supported-by-dependabot/supported-ecosystems-and-repositories) - List of supported package ecosystems - [Optimizing PR Creation](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/optimizing-pr-creation-version-updates) - Cooldown and grouping strategies diff --git a/.github/instructions/github-actions.instructions.md b/.github/instructions/github-actions.instructions.md index b234c95..6e9a5ca 100644 --- a/.github/instructions/github-actions.instructions.md +++ b/.github/instructions/github-actions.instructions.md @@ -50,7 +50,7 @@ jobs: persist-credentials: false ``` -This prevents credentials from being stored in the git config. +This prevents credentials from being stored in the Git config. ### Script Injection Prevention @@ -110,7 +110,7 @@ on: # Node.js projects - use .node-version or .nvmrc - uses: actions/setup-node@v4 with: - node-version-file: '.node-version' + node-version-file: ".node-version" ``` ### Conditional Execution @@ -156,7 +156,7 @@ Before finalizing any workflow changes: 1. Check existing `.github/workflows/` for established patterns 2. Check `.github/dependabot.yml` for dependency automation settings 3. Verify action versions via releases pages using GitHub MCP tools -4. Consider CI time and complexity tradeoffs +4. Consider CI time and complexity trade-offs ## Keeping Instructions Up-to-Date @@ -164,13 +164,13 @@ Before finalizing any workflow changes: --- -## Anti-Patterns +## Antipatterns -| Anti-Pattern | Why It's Problematic | Better Approach | -|--------------|---------------------|-----------------| -| Using version tags (`v4`) | Tags can be moved/deleted; supply chain risk | Pin to full 40-char commit SHA | -| Direct string interpolation | Script injection vulnerability | Use environment variables | -| Workflow-level `write` perms | Excessive access if job compromised | Minimal perms at workflow, increase per-job | -| Hardcoded language versions | Drift between local and CI | Use version files (go.mod, .node-version) | -| Assuming SHA validity | Outdated SHAs break workflows | Verify SHA against latest release | -| Missing YAML document start | Parser warnings and inconsistency | Always start with `---` | +| Antipattern | Why It's Problematic | Better Approach | +| ---------------------------- | -------------------------------------------- | ------------------------------------------- | +| Using version tags (`v4`) | Tags can be moved/deleted; supply chain risk | Pin to full 40-char commit SHA | +| Direct string interpolation | Script injection vulnerability | Use environment variables | +| Workflow-level `write` perms | Excessive access if job compromised | Minimal perms at workflow, increase per-job | +| Hardcoded language versions | Drift between local and CI | Use version files (go.mod, .node-version) | +| Assuming SHA validity | Outdated SHAs break workflows | Verify SHA against latest release | +| Missing YAML document start | Parser warnings and inconsistency | Always start with `---` | diff --git a/internal/ascii/generator.go b/internal/ascii/generator.go index dad02ec..d433a4d 100644 --- a/internal/ascii/generator.go +++ b/internal/ascii/generator.go @@ -57,6 +57,10 @@ func GenerateASCII(contributionGrid [][]types.ContributionDay, username string, // Fill the column for this week for dayIdx, day := range sortedDays { + // Bounds check to prevent slice index out of range + if dayIdx >= len(asciiGrid) { + continue + } if day.ContributionCount == -1 { asciiGrid[dayIdx][weekIdx] = FutureBlock } else { diff --git a/internal/errors/errors_test.go b/internal/errors/errors_test.go index 05ee43e..1613011 100644 --- a/internal/errors/errors_test.go +++ b/internal/errors/errors_test.go @@ -1,20 +1,22 @@ -package errors +package errors_test import ( "errors" "testing" + + skylineerrors "github.com/github/gh-skyline/internal/errors" ) func TestSkylineError_Error(t *testing.T) { tests := []struct { name string - err *SkylineError + err *skylineerrors.SkylineError want string }{ { name: "error with underlying error", - err: &SkylineError{ - Type: ValidationError, + err: &skylineerrors.SkylineError{ + Type: skylineerrors.ValidationError, Message: "invalid input", Err: errors.New("value out of range"), }, @@ -22,8 +24,8 @@ func TestSkylineError_Error(t *testing.T) { }, { name: "error without underlying error", - err: &SkylineError{ - Type: STLError, + err: &skylineerrors.SkylineError{ + Type: skylineerrors.STLError, Message: "failed to process STL", }, want: "[STL] failed to process STL", @@ -61,8 +63,8 @@ func TestWrap(t *testing.T) { }, { name: "wrap SkylineError preserves type", - err: &SkylineError{ - Type: ValidationError, + err: &skylineerrors.SkylineError{ + Type: skylineerrors.ValidationError, Message: "original message", Err: errors.New("base error"), }, @@ -73,7 +75,7 @@ func TestWrap(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := Wrap(tt.err, tt.message) + got := skylineerrors.Wrap(tt.err, tt.message) if tt.wantNil { if got != nil { t.Errorf("Wrap() = %v, want nil", got) @@ -93,21 +95,21 @@ func TestWrap(t *testing.T) { func TestNew(t *testing.T) { tests := []struct { name string - errType ErrorType + errType skylineerrors.ErrorType message string err error want string }{ { name: "new error without underlying error", - errType: ValidationError, + errType: skylineerrors.ValidationError, message: "validation failed", err: nil, want: "[VALIDATION] validation failed", }, { name: "new error with underlying error", - errType: NetworkError, + errType: skylineerrors.NetworkError, message: "network timeout", err: errors.New("connection refused"), want: "[NETWORK] network timeout: connection refused", @@ -116,7 +118,7 @@ func TestNew(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := New(tt.errType, tt.message, tt.err) + got := skylineerrors.New(tt.errType, tt.message, tt.err) if got.Error() != tt.want { t.Errorf("New() error = %v, want %v", got.Error(), tt.want) } @@ -136,34 +138,34 @@ func TestNew(t *testing.T) { func TestSkylineError_Is(t *testing.T) { tests := []struct { name string - err *SkylineError + err *skylineerrors.SkylineError target error want bool }{ { name: "matching error types", - err: &SkylineError{ - Type: ValidationError, + err: &skylineerrors.SkylineError{ + Type: skylineerrors.ValidationError, }, - target: &SkylineError{ - Type: ValidationError, + target: &skylineerrors.SkylineError{ + Type: skylineerrors.ValidationError, }, want: true, }, { name: "different error types", - err: &SkylineError{ - Type: ValidationError, + err: &skylineerrors.SkylineError{ + Type: skylineerrors.ValidationError, }, - target: &SkylineError{ - Type: NetworkError, + target: &skylineerrors.SkylineError{ + Type: skylineerrors.NetworkError, }, want: false, }, { name: "non-SkylineError target", - err: &SkylineError{ - Type: ValidationError, + err: &skylineerrors.SkylineError{ + Type: skylineerrors.ValidationError, }, target: errors.New("standard error"), want: false, @@ -183,13 +185,13 @@ func TestSkylineError_Unwrap(t *testing.T) { baseErr := errors.New("base error") tests := []struct { name string - err *SkylineError + err *skylineerrors.SkylineError wantErr error }{ { name: "with underlying error", - err: &SkylineError{ - Type: ValidationError, + err: &skylineerrors.SkylineError{ + Type: skylineerrors.ValidationError, Message: "test message", Err: baseErr, }, @@ -197,8 +199,8 @@ func TestSkylineError_Unwrap(t *testing.T) { }, { name: "without underlying error", - err: &SkylineError{ - Type: ValidationError, + err: &skylineerrors.SkylineError{ + Type: skylineerrors.ValidationError, Message: "test message", }, wantErr: nil, From 1b7ddb277ab9a45a93fdb6ae355c7b44473e0fb6 Mon Sep 17 00:00:00 2001 From: Chris Reddington <791642+chrisreddington@users.noreply.github.com> Date: Tue, 27 Jan 2026 09:55:40 +0000 Subject: [PATCH 09/10] Add .textlintignore file and improve ASCII generation bounds checking --- .textlintignore | 2 ++ internal/ascii/generator.go | 12 +++++++----- internal/errors/errors.go | 1 + 3 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 .textlintignore diff --git a/.textlintignore b/.textlintignore new file mode 100644 index 0000000..68eb0d7 --- /dev/null +++ b/.textlintignore @@ -0,0 +1,2 @@ +# Ignore instruction files that contain technical terms in code examples +.github/instructions/ diff --git a/internal/ascii/generator.go b/internal/ascii/generator.go index d433a4d..8adde27 100644 --- a/internal/ascii/generator.go +++ b/internal/ascii/generator.go @@ -56,11 +56,13 @@ func GenerateASCII(contributionGrid [][]types.ContributionDay, username string, sortedDays, nonZeroCount := sortContributionDays(week, now) // Fill the column for this week - for dayIdx, day := range sortedDays { - // Bounds check to prevent slice index out of range - if dayIdx >= len(asciiGrid) { - continue - } + // Limit iteration to valid asciiGrid indices (max 7 rows for days of week) + maxDayIdx := len(asciiGrid) + if len(sortedDays) < maxDayIdx { + maxDayIdx = len(sortedDays) + } + for dayIdx := 0; dayIdx < maxDayIdx; dayIdx++ { + day := sortedDays[dayIdx] if day.ContributionCount == -1 { asciiGrid[dayIdx][weekIdx] = FutureBlock } else { diff --git a/internal/errors/errors.go b/internal/errors/errors.go index fc52f8a..278abcf 100644 --- a/internal/errors/errors.go +++ b/internal/errors/errors.go @@ -1,4 +1,5 @@ // Package errors provides custom error types and utilities for the Skyline application. +//nolint:revive // Package name is intentional for clear error semantics within this project package errors import ( From cc12b6f298ac3093d5b91480f9be5e6cdbaacc42 Mon Sep 17 00:00:00 2001 From: Chris Reddington <791642+chrisreddington@users.noreply.github.com> Date: Tue, 27 Jan 2026 10:06:38 +0000 Subject: [PATCH 10/10] Textlintignore update and improve comments in generator and errors packages --- .github/linters/.textlintignore | 2 ++ .textlintignore | 2 +- internal/ascii/generator.go | 4 ++-- internal/errors/errors.go | 1 + 4 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 .github/linters/.textlintignore diff --git a/.github/linters/.textlintignore b/.github/linters/.textlintignore new file mode 100644 index 0000000..5fb5513 --- /dev/null +++ b/.github/linters/.textlintignore @@ -0,0 +1,2 @@ +# Ignore instruction files that contain technical terms in code examples +.github/instructions/**/*.md diff --git a/.textlintignore b/.textlintignore index 68eb0d7..5fb5513 100644 --- a/.textlintignore +++ b/.textlintignore @@ -1,2 +1,2 @@ # Ignore instruction files that contain technical terms in code examples -.github/instructions/ +.github/instructions/**/*.md diff --git a/internal/ascii/generator.go b/internal/ascii/generator.go index 8adde27..3c18211 100644 --- a/internal/ascii/generator.go +++ b/internal/ascii/generator.go @@ -64,13 +64,13 @@ func GenerateASCII(contributionGrid [][]types.ContributionDay, username string, for dayIdx := 0; dayIdx < maxDayIdx; dayIdx++ { day := sortedDays[dayIdx] if day.ContributionCount == -1 { - asciiGrid[dayIdx][weekIdx] = FutureBlock + asciiGrid[dayIdx][weekIdx] = FutureBlock // #nosec G602 -- bounds checked by maxDayIdx calculation above } else { normalized := 0.0 if maxContributions != 0 { normalized = float64(day.ContributionCount) / float64(maxContributions) } - asciiGrid[dayIdx][weekIdx] = getBlock(normalized, dayIdx, nonZeroCount) + asciiGrid[dayIdx][weekIdx] = getBlock(normalized, dayIdx, nonZeroCount) // #nosec G602 -- bounds checked by maxDayIdx calculation above } } } diff --git a/internal/errors/errors.go b/internal/errors/errors.go index 278abcf..06665ba 100644 --- a/internal/errors/errors.go +++ b/internal/errors/errors.go @@ -1,4 +1,5 @@ // Package errors provides custom error types and utilities for the Skyline application. +// //nolint:revive // Package name is intentional for clear error semantics within this project package errors