Skip to content
BETAGuardrails are in beta. The library, the configuration format and the CLI command can still change.

Guardrails / Collectors

Ruby project

The Bundler project in the project directory: the Ruby version it asks for, the gem sources it resolves from, the gems each manifest declares with their groups and origins, and the lock file beside them. The Gemfile is Ruby rather than a declaration, so what it declares conditionally is not seen and scanned says so.

Facts keyruby
Versionv1
Scriptruby.py
Timeout30 seconds

Inputs

InputDescriptionDefaultEnvironment
projectDirDirectory holding the project, relative to the directory the CLI runs in..GUARDRAIL_INPUT_PROJECTDIR

A guardrail that declares an input of the same name passes it through, so the guardrail's configuration in buildnote.json is what decides these values.

A guardrail asks for these facts by name, and reads them back the same way:

json
{
  "collect": ["ruby"]
}
python
ruby = guardrail.facts("ruby")

Facts

The document ruby collects. A path carrying [] is an entry of the list before it, and one carrying [path] is a key of the object before it.

FactMeaning
directoryThe projectDir input, as the guardrail configured it.
existsWhether that directory is there. Nothing else is collected when it is not.
manifestPath of the primary manifest, relative to projectDir: the Gemfile when there is one, otherwise the gemspec.
sourcesEvery manifest that was read, in the order they were read.
scannedEvery manifest that is Ruby rather than a declaration and was read by pattern. A gem added inside a condition, a loop or an eval is not seen, so a guardrail reading dependencies from one of these is reading a floor rather than the whole list.
declaredThe Ruby version the project asks for, or null when it asks for none. .ruby-version wins over the ruby directive, because it is what a developer's shell and the runner's version manager both read, and the ruby directive wins over a gemspec's required_ruby_version, which is the floor the gem supports rather than the version this checkout runs.
declared.versionConstraint exactly as written, such as 3.3.1 or >= 3.2.
declared.sourceFile declaring it, relative to projectDir.
declared.pinnedWhether the constraint names one exact version rather than a range. A ~>, a >= or a * is not pinned.
bundlerVersion of Bundler Gemfile.lock records as the one that wrote it, or null when no lock file is committed.
sources_declaredEvery gem source the Gemfile names, such as https://rubygems.org. A second source is what a dependency confusion attack needs.
projectsThe one gem the checkout declares, or the project directory itself when it declares none. Bundler has no workspaces.
projects[].pathDirectory of the gem, relative to projectDir, always ..
projects[].manifestIts gemspec, relative to projectDir, or the Gemfile when the checkout carries no gemspec.
projects[].nameName the gemspec declares, or null when there is none to read it from.
dependenciesWhat the manifests declare, split by whether the project asks for it itself.
dependencies.directEvery gem call the reader saw, in the order they appear.
dependencies.direct[].nameGem name, such as rails.
dependencies.direct[].versionRequirement exactly as written, such as ~> 7.1, or null when the call names none and any version will do.
dependencies.direct[].scopesThe Bundler groups the gem is in: default when the call is at the top level, otherwise the group it sits inside, such as development or test.
dependencies.direct[].sourceManifest declaring it, relative to projectDir.
dependencies.direct[].pinnedWhether the requirement names one exact version. A ~>, a >=, a git: or a path: option is not pinned.
dependencies.direct[].originWhere it comes from: registry, git when the call carries a git: or github: option, or path when it carries a path: option.
dependencies.transitiveAlways empty. What Gemfile.lock resolves is not read: lockfiles says whether one is committed.
lockfilesGemfile.lock when it is committed, relative to projectDir. An application without one resolves differently on every deploy.
unparsedEvery manifest the reader could not open, so a guardrail can tell a project that declares nothing from one nobody could read.
unparsed[].pathPath of that manifest, relative to projectDir.
unparsed[].reasonWhat stopped the reader.

A collector that cannot finish prints what it had along with an incomplete key saying why, so the facts below the point it stopped are absent. A check that cares reads incomplete before the rest.

Example facts

The example facts collected by ruby collector:

json
{
  "directory": ".",
  "exists": true,
  "manifest": "Gemfile",
  "sources": [
    "Gemfile"
  ],
  "scanned": [
    "Gemfile"
  ],
  "declared": {
    "version": "3.3.1",
    "source": "Gemfile",
    "pinned": true
  },
  "bundler": "2.5.9",
  "sources_declared": [
    "https://rubygems.org"
  ],
  "projects": [
    {
      "path": ".",
      "manifest": "Gemfile",
      "name": null
    }
  ],
  "dependencies": {
    "direct": [
      {
        "name": "rails",
        "version": "~> 7.1.3",
        "scopes": [
          "default"
        ],
        "source": "Gemfile",
        "pinned": false,
        "origin": "registry"
      },
      {
        "name": "pg",
        "version": "1.5.6",
        "scopes": [
          "default"
        ],
        "source": "Gemfile",
        "pinned": true,
        "origin": "registry"
      },
      {
        "name": "puma",
        "version": ">= 6.4",
        "scopes": [
          "default"
        ],
        "source": "Gemfile",
        "pinned": false,
        "origin": "registry"
      },
      {
        "name": "rspec-rails",
        "version": "~> 6.1",
        "scopes": [
          "development",
          "test"
        ],
        "source": "Gemfile",
        "pinned": false,
        "origin": "registry"
      },
      {
        "name": "rubocop",
        "version": null,
        "scopes": [
          "development"
        ],
        "source": "Gemfile",
        "pinned": false,
        "origin": "registry"
      }
    ],
    "transitive": []
  },
  "lockfiles": [
    "Gemfile.lock"
  ],
  "unparsed": []
}

Collected for

GuardrailCategoryInputs
ruby/lockfile-committedrubyprojectDir
ruby/no-git-dependenciesrubyprojectDir
ruby/single-gem-sourcerubyprojectDir
ruby/version-declaredrubyprojectDir

All collectors

Buildnote Limited
Registered in England and Wales, Reg: 16140412