Add a cop for ENV reads in library code (A6) #1506
Labels
No labels
P0
P1
P2
P3
bug
category/code-change
category/cross-repo
category/eval-run
category/investigation
category/no-test-target
category/owner-ruling
category/prose-artifact
category/recurring-chore
category/structure
category/umbrella
crc-refactor
create
delete
enhancement
filed-by/agent
filed-by/user
frozen
lint-rule
needs-info
needs-triage
next
plugin/cc-architect
plugin/os
plugin/os-adr
plugin/os-aidd-lint
plugin/os-backlog
plugin/os-context
plugin/os-doc-hygiene
plugin/os-sdlc
plugin/os-vault
project/cc-os
ready-for-agent
ready-for-human
recurring
review
rule-proposal
update
waiting
wayfinder:grilling
wayfinder:map
wayfinder:map
wayfinder:research
wayfinder:task
wayfinder:task
wontfix
worklist/deviations
worklist/lint-rule
worklist/new-implement-build
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
jared/cc-os#1506
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
No cop flags an ENV read inside a library method body.
Sdlc/RequireInsideCode/LoadTimeStateflags only load-time ENV. Principle 9 names ENV as the outside world. Only the entry script reads the outside world.Related: #1407, #1386, #1041 each fix one ENV site by hand; the cop's fixtures overlap their sites.
Reproduce
n/a: design ticket. The cop does not exist yet.
Approach
Jared ruled on 2026-11-02 that an
env: ENVdefault argument is a library ENV read. Onlybin/reads ENV and passes it in. A keyword default that builds a collaborator object stays allowed. The lens rule is A6 inplugins/os-sdlc/skills/lens-architecture/SKILL.md.LoadTimeStatehasCONSTANTS = Set[:ENV, :Warning].freezeatplugins/os-sdlc/lib/os_sdlc/cops/require_inside_code/load_time_state.rb:8.The cop must fire on these known sites:
plugins/os-backlog/lib/backlog/forgejo_backend.rb:8:def initialize(client: nil, env: ENV)plugins/os-backlog/lib/backlog/cli.rb:17:@env = config.fetch(:env, ENV)plugins/os-backlog/lib/backlog/inspector/executable_path.rb:6:def initialize(path = ENV.fetch("PATH", ""))plugins/os-sdlc/lib/os_sdlc/tracker/forgejo_api.rb:11:::Forgejo::Client.new(url: "https://#{HOST}", api_key: ENV.fetch("FORGEJO_TOKEN"))plugins/os-sdlc/lib/os_sdlc/tracker/issue_source/github.rb:23:@client ||= Octokit::Client.new(access_token: ENV.fetch("GITHUB_TOKEN"))plugins/os-sdlc/lib/os_sdlc/process_io/invocation.rb:7:{ cwd: Dir.pwd, stdin: $stdin, stdout: $stdout, stderr: $stderr, env: ENV.to_h }plugins/os-sdlc/lib/os_sdlc/system_model/recorder/install.rb:20:install.call(root: ENV.fetch(install::ROOT), output: ENV.fetch(install::OUTPUT)) if ENV.key?(install::OUTPUT)Open question: the first lines of the plugin lib root files assign
ENV["BUNDLE_GEMFILE"] ||=. The sites areplugins/os-adr/lib/adr.rb:3,plugins/os-backlog/lib/backlog.rb:3,plugins/os-me/lib/os_me.rb:3, andplugins/os-sdlc/lib/os_sdlc.rb:7. The ticket must rule whether the cop flags these lines or whether the cop matches them by exact value.Cop criteria. All criteria are required.
Required work:
LibraryEnvReadinplugins/os-sdlc/lib/os_sdlc/cops/require_inside_code/library_env_read.rbFORGEJO_TOKENinplugins/os-sdlc/tests/cops/**/*.rbOrchestrator work: Wire the cop in
plugins/os-sdlc/.rubocop.yml, and add a lesson for A6.Acceptance criteria
env: ENVas a default argument, when the cop runs, then it reports an offense.ENV.fetchin a method body, when the cop runs, then it reports an offense.bin/script that reads ENV, when the cop runs, then it reports no offense.ENV["BUNDLE_GEMFILE"] ||=lines, when the cop runs, then the result matches the ruling that the ticket records.Owner sketch
Origin
VERDICT: CREATE
jared referenced this issue2026-11-07 18:59:04 +00:00