wave5: vagrant-0001 flagship + 32-target CI/CD/IaC scan survey
vagrant-0001: bundler.rb plugin loader runs Array#include? against plugins.keys / system_plugins inside per-spec loops. O(S*P) per vagrant command. Fix: hoist Set.new outside the loop, O(1) per spec lookup. Bench: 127x at S=2000 P=1000. wave5-cicd-iac-survey.md: documents 32 projects scanned across deployment (Spinnaker, fluxcd, Argo Rollouts/Events), modern CI/CD (Earthly, Dagger, Buck2), container runtime (containerd, crun, skopeo, ko, kaniko, buildah), local k8s (kind, minikube, k3s), IaC + testing (Packer, Vagrant, ansible-lint, Molecule, InSpec, Terratest), contract/mutation testing (Pact, Stryker, mutmut, PIT), security (Semgrep, Bandit, gosec), Java quality (Spotbugs, Checkstyle, chart-testing). Clean-scan honor roll +4: chart-testing, kind, ko, pact-ruby.
This commit is contained in:
parent
b9c6ea007d
commit
33cc466b3a
9 changed files with 345 additions and 1 deletions
72
docs/tickets/vagrant-0001-bundler-plugin-include-in-loop.md
Normal file
72
docs/tickets/vagrant-0001-bundler-plugin-include-in-loop.md
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
# vagrant-0001: Bundler plugin loader — O(S×P) Array#include? in loop
|
||||
|
||||
**Target:** hashicorp/vagrant
|
||||
**Severity:** MEDIUM
|
||||
**CWE:** CWE-407 (Inefficient Algorithmic Complexity)
|
||||
**MOAD:** MOAD-0001 (A Sedimentary Defect)
|
||||
**File:** `lib/vagrant/bundler.rb:469-471, 533-534`
|
||||
**Language:** Ruby
|
||||
**Status:** open
|
||||
|
||||
## Description
|
||||
|
||||
Vagrant's `Bundler` orchestrates plugin resolution and gem-spec selection on every `vagrant` command run. Two paths walk a list of resolved gem specs and check membership against a plugin/system Array via `Array#include?` (O(P) linear scan):
|
||||
|
||||
```ruby
|
||||
# bundler.rb:469-471 — pruning the solution to declared plugins
|
||||
solution.find_all do |spec|
|
||||
plugins.keys.include?(spec.name)
|
||||
end
|
||||
|
||||
# bundler.rb:533-534 — adding strict-dependency enforcement specs
|
||||
plugin_deps += vagrant_internal_specs.map do |spec|
|
||||
if Vagrant.in_bundler?
|
||||
next if system_plugins.include?(spec.name)
|
||||
next if spec.default_gem?
|
||||
end
|
||||
...
|
||||
end
|
||||
```
|
||||
|
||||
For S resolved specs and P plugins (plus I internal vagrant specs and S system plugins), per-run cost is O(S×P) and O(I×S). Vagrant ships ~30 internal specs by default; users with many third-party plugins push P into the hundreds.
|
||||
|
||||
This runs on **every vagrant command** that touches the plugin path (`vagrant up`, `vagrant ssh`, `vagrant plugin list`, etc.) — slow startup compounds across every developer interaction.
|
||||
|
||||
## Root Cause
|
||||
|
||||
Both `plugins.keys` and `system_plugins` are plain Ruby Arrays. `Array#include?` is O(N) linear scan with `==` on each entry. Inside the per-spec block, total cost scales as O(S×P).
|
||||
|
||||
## Fix
|
||||
|
||||
Convert the lookup arrays to Sets once outside the loop. `Set#include?` is O(1) via hash.
|
||||
|
||||
```ruby
|
||||
# Hoist:
|
||||
plugin_name_set = Set.new(plugins.keys)
|
||||
|
||||
solution.find_all do |spec|
|
||||
plugin_name_set.include?(spec.name) # O(1)
|
||||
end
|
||||
|
||||
# Same treatment for system_plugins:
|
||||
system_plugins_set = Set.new(system_plugins)
|
||||
|
||||
plugin_deps += vagrant_internal_specs.map do |spec|
|
||||
if Vagrant.in_bundler?
|
||||
next if system_plugins_set.include?(spec.name) # O(1)
|
||||
next if spec.default_gem?
|
||||
end
|
||||
...
|
||||
end
|
||||
```
|
||||
|
||||
`require "set"` is already at the top of bundler.rb (line 6). Total cost drops to O(S+P).
|
||||
|
||||
## Severity Note
|
||||
|
||||
Per-vagrant-command overhead. Impact scales linearly with plugin count × resolved spec count. Negligible for one-plugin setups, measurable for multi-plugin developer environments. Cleanup-grade priority but high-frequency — every developer pays this on every command.
|
||||
|
||||
## Complexity Gate
|
||||
|
||||
- S=P=500: fixed must complete in <5ms
|
||||
- k-scaling 5×: time ratio must be <17.5×
|
||||
Loading…
Add table
Add a link
Reference in a new issue