Skip to content

chore(ci): add pathconcat custom linter plugin#3266

Open
jakedoublev wants to merge 2 commits intomainfrom
feat/pathconcat-linter
Open

chore(ci): add pathconcat custom linter plugin#3266
jakedoublev wants to merge 2 commits intomainfrom
feat/pathconcat-linter

Conversation

@jakedoublev
Copy link
Copy Markdown
Contributor

@jakedoublev jakedoublev commented Apr 7, 2026

Summary

  • Integrates pathconcat as a golangci-lint module plugin
  • Detects string-based path/URL concatenation (x + "/" + y, fmt.Sprintf("%s/%s", ...), strings.Join(parts, "/")) and suggests path.Join, filepath.Join, or url.JoinPath
  • Suppresses false positives for FQN construction (/attr/, /value/, /obl/), connection strings, and scheme prefixes

Changes

  • .custom-gcl.yml — build config for custom golangci-lint binary with the plugin
  • .golangci.yaml — enable pathconcat linter with ignore-strings for FQN patterns
  • Makefilego-lint target now builds custom-gcl first, then uses it
  • .github/workflows/checks.yaml — build custom binary in CI, restore --new-from-rev for PR-only issue reporting
  • .gitignore — ignore the custom-gcl binary

Test plan

  • CI passes with custom binary build
  • make lint builds custom-gcl and runs successfully
  • PR annotations appear for lint findings via actions/setup-go problem matcher
  • FQN patterns in lib/identifier/obligation.go are not flagged

Summary by CodeRabbit

  • Chores
    • Added a new linting configuration that flags string path/URL concatenation and provides recommendations.
    • Introduced a repository-level custom lint runner and updated lint targets to use it.
    • Updated CI workflows to install and run the custom lint tooling as part of checks.
    • Updated ignore rules to exclude the custom lint runner artifacts.

Integrates github.com/jakedoublev/pathconcat as a golangci-lint module
plugin to detect string-based path/URL concatenation (x + "/" + y,
fmt.Sprintf with path separators, strings.Join with "/") and suggest
path.Join, filepath.Join, or url.JoinPath instead.

- Add .custom-gcl.yml to build custom golangci-lint binary with plugin
- Enable pathconcat in .golangci.yaml with ignore-strings for FQN patterns
- Update Makefile go-lint target to build and use custom-gcl binary
- Update CI workflow to build custom binary and restore --new-from-rev

Signed-off-by: jakedoublev <jake.vanvorhis@virtru.com>
@jakedoublev jakedoublev requested review from a team as code owners April 7, 2026 17:13
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the project's static analysis capabilities by introducing a custom golangci-lint plugin designed to enforce safer path and URL construction practices. By automating the build of a custom linter binary and integrating it into the existing linting workflow, the changes ensure consistent code quality while allowing for necessary exceptions through configuration.

Highlights

  • Linter Integration: Integrated the pathconcat plugin into golangci-lint to identify and suggest safer alternatives for string-based path and URL concatenation.
  • Configuration Updates: Updated .golangci.yaml to enable the new linter and configured ignore-strings to prevent false positives on specific FQN patterns.
  • Build Process: Modified the Makefile to automatically build a custom golangci-lint binary and updated the go-lint target to utilize this custom binary.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Ignored Files
  • Ignored by pattern: .github/workflows/** (1)
    • .github/workflows/checks.yaml
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.


Paths joined by strings can be a snare, Leading to bugs beyond compare. With a new plugin to check the way, Our code stays clean and safe today.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-actions github-actions bot added the comp:ci Github Actions Work label Apr 7, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 7, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8d0d5b82-47af-4330-b34f-0194dba9a46c

📥 Commits

Reviewing files that changed from the base of the PR and between b0e385a and 619d077.

📒 Files selected for processing (1)
  • .custom-gcl.yml

📝 Walkthrough

Walkthrough

Adds a custom golangci-lint wrapper and enables a pathconcat plugin; integrates the custom linter into CI, the Makefile, and .gitignore, and provides plugin configuration in .golangci.yaml and a pinned .custom-gcl.yml.

Changes

Cohort / File(s) Summary
Custom linter config
\.custom-gcl\.yml, \.golangci\.yaml
Adds .custom-gcl.yml pinning version v2.8.0 and a plugin github.com/jakedoublev/pathconcat@v0.3.0. Enables pathconcat in .golangci.yaml with settings.custom.pathconcat and an ignore-strings list ("/attr/", "/value/", "/obl/").
CI workflow changes
.github/workflows/checks.yaml
Replaces the golangci-lint GitHub Action with explicit go install of golangci-lint (v2.8.0), adds steps to build/install the custom-gcl wrapper, and runs ${{ github.workspace }}/custom-gcl run with -c ${{ github.workspace }}/.golangci.yaml and conditional PR new-from-rev args.
Build system updates
Makefile
Adds custom-gcl Make target and updates go-lint to depend on custom-gcl and invoke $(ROOT_DIR)/custom-gcl run ... instead of calling golangci-lint run directly.
Repo ignore list
.gitignore
Adds custom-gcl to .gitignore.
sequenceDiagram
    participant Dev as Developer
    participant GH as GitHub Actions
    participant GoTool as Go toolchain
    participant Build as Build/Wrapper (custom-gcl)
    participant Linter as golangci-lint
    participant Repo as Repository

    Dev->>Repo: push PR / commit
    GH->>Repo: checkout code
    GH->>GoTool: go install golangci-lint@v2.8.0
    GH->>GoTool: go build -o custom-gcl ./path/to/wrapper
    GH->>Build: run ./custom-gcl run -c .golangci.yaml (with PR new-from-rev if applicable)
    Build->>Linter: invoke golangci-lint with configured plugins (pathconcat)
    Linter->>Build: lint results
    Build->>GH: exit code / annotations
    GH->>Dev: CI status/results
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I nibble queues of linting hay,
I hop where path-joins go astray,
A plugin pinned, a wrapper dressed,
CI hums while I take a rest,
Hooray—clean paths and carrots for play! 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding a pathconcat custom linter plugin to the CI workflow.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/pathconcat-linter

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added the size/s label Apr 7, 2026
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request integrates a custom golangci-lint plugin called pathconcat to detect string path/URL concatenation. It introduces a .custom-gcl.yml configuration, updates .golangci.yaml to enable the linter, and modifies the Makefile to build and use the custom linter binary. Feedback was provided to optimize the Makefile by removing the custom-gcl target from .PHONY to prevent redundant builds and adding .custom-gcl.yml as a dependency for that target to ensure the binary is correctly updated when configuration changes.

# To run all lint checks: `LINT_OPTIONS= make lint`

.PHONY: all build clean connect-wrapper-generate docker-build fix fmt go-lint license lint proto-generate proto-lint sdk/sdk test tidy toolcheck
.PHONY: all build clean connect-wrapper-generate custom-gcl docker-build fix fmt go-lint license lint proto-generate proto-lint sdk/sdk test tidy toolcheck
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The custom-gcl target should not be marked as .PHONY. Since it produces a binary file named custom-gcl, marking it as .PHONY forces the custom linter to be rebuilt every time make lint or make go-lint is called. Building a custom golangci-lint binary is a relatively slow process as it involves compiling plugins, so avoiding unnecessary rebuilds will improve developer productivity and CI efficiency.

.PHONY: all build clean connect-wrapper-generate docker-build fix fmt go-lint license lint proto-generate proto-lint sdk/sdk test tidy toolcheck

Comment on lines +59 to +60
custom-gcl:
golangci-lint custom
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To ensure the custom linter binary is rebuilt when its configuration changes, add .custom-gcl.yml as a dependency for the custom-gcl target. This, combined with removing it from .PHONY, ensures the binary is only built when necessary. Additionally, consider adding custom-gcl to your clean target (though it is outside the current diff) to ensure the binary is removed during cleanup.

custom-gcl: .custom-gcl.yml
	golangci-lint custom

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/checks.yaml:
- Around line 90-93: Replace per-matrix-step compilation by adding a dedicated
prep job that builds the custom golangci-lint binary once and publishes it as an
artifact (e.g., "custom-gcl"); then change the matrix jobs that currently run
the steps named "install golangci-lint" and "build custom golangci-lint" to
instead download that artifact (or restore from cache) before running linting.
Ensure the prep job runs before the matrix (use needs or job dependencies),
upload the built binary with upload-artifact, and in each matrix job use
download-artifact (or cache) to reuse the same "custom-gcl" binary rather than
rebuilding in every leg.

In @.golangci.yaml:
- Around line 77-85: Add short inline rationale comments explaining why the
three broad ignore-strings ("/attr/", "/value/", "/obl/") exist so future
editors don't remove or change them inadvertently; update the .golangci.yaml
custom -> pathconcat -> settings -> ignore-strings block to include one-line
comments for each pattern describing what cases they suppress (e.g., internal
API paths, known URL fragments, or legacy routes) and a note about the risk of
narrowing them, referencing the keys "custom", "pathconcat", "settings", and
"ignore-strings" so reviewers can find the explanation easily.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4c682650-d9a3-4635-b921-b78529b9dd42

📥 Commits

Reviewing files that changed from the base of the PR and between ea5f66e and b0e385a.

📒 Files selected for processing (5)
  • .custom-gcl.yml
  • .github/workflows/checks.yaml
  • .gitignore
  • .golangci.yaml
  • Makefile

Comment on lines +90 to +93
- name: install golangci-lint
run: go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.8.0
- name: build custom golangci-lint
run: golangci-lint custom
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Build custom-gcl once per workflow and reuse across matrix jobs.

Compiling the custom binary in every matrix leg adds avoidable CI time. Consider a dedicated prep job that builds custom-gcl once and shares it via artifact/cache.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/checks.yaml around lines 90 - 93, Replace per-matrix-step
compilation by adding a dedicated prep job that builds the custom golangci-lint
binary once and publishes it as an artifact (e.g., "custom-gcl"); then change
the matrix jobs that currently run the steps named "install golangci-lint" and
"build custom golangci-lint" to instead download that artifact (or restore from
cache) before running linting. Ensure the prep job runs before the matrix (use
needs or job dependencies), upload the built binary with upload-artifact, and in
each matrix job use download-artifact (or cache) to reuse the same "custom-gcl"
binary rather than rebuilding in every leg.

Comment on lines +77 to +85
custom:
pathconcat:
type: module
description: "Detects string path/URL concatenation; suggests filepath.Join, path.Join, or url.JoinPath"
settings:
ignore-strings:
- "/attr/"
- "/value/"
- "/obl/"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Add rationale comments for broad ignore-strings patterns.

Line 82–85 uses substring suppressions that are intentionally broad; a short inline note will reduce future accidental edits/regressions.

📝 Suggested clarity update
     custom:
       pathconcat:
         type: module
         description: "Detects string path/URL concatenation; suggests filepath.Join, path.Join, or url.JoinPath"
         settings:
+          # Suppress known FQN token patterns that are not filesystem/URL path construction.
           ignore-strings:
             - "/attr/"
             - "/value/"
             - "/obl/"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
custom:
pathconcat:
type: module
description: "Detects string path/URL concatenation; suggests filepath.Join, path.Join, or url.JoinPath"
settings:
ignore-strings:
- "/attr/"
- "/value/"
- "/obl/"
custom:
pathconcat:
type: module
description: "Detects string path/URL concatenation; suggests filepath.Join, path.Join, or url.JoinPath"
settings:
# Suppress known FQN token patterns that are not filesystem/URL path construction.
ignore-strings:
- "/attr/"
- "/value/"
- "/obl/"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.golangci.yaml around lines 77 - 85, Add short inline rationale comments
explaining why the three broad ignore-strings ("/attr/", "/value/", "/obl/")
exist so future editors don't remove or change them inadvertently; update the
.golangci.yaml custom -> pathconcat -> settings -> ignore-strings block to
include one-line comments for each pattern describing what cases they suppress
(e.g., internal API paths, known URL fragments, or legacy routes) and a note
about the risk of narrowing them, referencing the keys "custom", "pathconcat",
"settings", and "ignore-strings" so reviewers can find the explanation easily.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 7, 2026

Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 198.214783ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 103.088982ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 382.040294ms
Throughput 261.75 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 40.091591691s
Average Latency 399.247431ms
Throughput 124.71 requests/second

Signed-off-by: jakedoublev <jake.vanvorhis@virtru.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 7, 2026

Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 197.557866ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 102.351959ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 395.775483ms
Throughput 252.67 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 42.22899717s
Average Latency 419.889913ms
Throughput 118.40 requests/second

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 7, 2026

⚠️ Govulncheck found vulnerabilities ⚠️

The following modules have known vulnerabilities:

  • service
  • tests-bdd

See the workflow run for details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp:ci Github Actions Work size/s

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant