Pipeline jobs declare a timeout
gitlab/job-timeout-set@v1
Every job declares how long it may run, so a hung job is cut off rather than holding a runner until the project's own limit.
| Id | gitlab/job-timeout-set |
| Version | v1 |
| Category | gitlab |
| Default severity | info |
| Interpreter | python3 |
| Timeout | 30 seconds |
| Violations tolerated | 0 |
| Collects | gitlab |
Collectors
This guardrail gathers nothing itself. It depends on the collectors below, which the CLI runs once per build before any check, and reads what they found out of GUARDRAIL_FACTS. A collector that collects nothing skips this guardrail rather than failing it.
| Collector | Gathers | Inputs it is given |
|---|---|---|
gitlab | What GitLab itself reads out of the repository: the .gitlab-ci.yml, read as GitLab writes it, and the CODEOWNERS file, read as sections of rules. For the pipeline, the stages it declares, what it includes, and for every job the stage it sits in, the image and runner tags it asks for, how long it may run, the rules that decide whether it runs at all, and each script section with the variables it interpolates. For CODEOWNERS, every section with whether it is optional and how many approvals it needs, the rules under each, and the owners that apply to the paths a guardrail asks about, resolved per section the way GitLab resolves them. Names and shapes only, never a secret, a variable value or an environment value. | pipelines |
The inputs above are this guardrail's own, passed straight through. Configuring one in buildnote.json changes what is collected, and two guardrails configured the same way share the one collection.
Configuration
{
"guardrails": {
"failOn": "error",
"comment": true,
"checks": [
{
"use": "gitlab/job-timeout-set@v1",
"severity": "info",
"with": {
"pipelines": ".gitlab-ci.yml,.gitlab-ci.yaml",
"maxMinutes": "60"
},
"exemptions": []
}
]
}
}Inputs
| Input | Description | Default | Environment variable |
|---|---|---|---|
pipelines | Comma separated globs naming the GitLab CI files to read. | .gitlab-ci.yml,.gitlab-ci.yaml | GUARDRAIL_INPUT_PIPELINES |
maxMinutes | Longest timeout accepted. A job declaring more than this is treated as declaring none. | 60 | GUARDRAIL_INPUT_MAXMINUTES |
How to fix
Declare one on each job:
build:
timeout: 15 minutes
script:
- ./gradlew checkA job that declares none takes the project's timeout, which lives in GitLab's settings rather than in this repository, so nobody reading the pipeline can tell what it is. A job that hangs holds a runner for all of it, which on a fleet of your own is a queue nobody can clear and on GitLab's shared runners is minutes off your quota.
More in gitlab
gitlab/codeowners-catch-all. A section whose approval is required declares a rule matching every path, so a file nobody thought about still has an owner who has to approve it.gitlab/codeowners-no-unowned-rules. No rule inCODEOWNERSends up with an empty set of owners, counting the default owners its section header hands down, so no section claims a path it names nobody for.gitlab/codeowners-owners-per-rule. Every rule inCODEOWNERSends up with at least the minimum owners and no more than the maximum, counting the default owners its section header hands down, so review is neither one person's bus factor nor everybody's problem.gitlab/codeowners-parses. Every line ofCODEOWNERSthat is not a comment reads either as a section header or as a rule, so no ownership is silently lost to a line GitLab ignores.gitlab/codeowners-present. The project carries aCODEOWNERSfile in one of the three places GitLab reads one from, and at least one section of it declares a rule, so every change has somebody to review it.gitlab/codeowners-team-owned. Every rule inCODEOWNERSends up owned by at least one GitLab group, so ownership survives the people currently in it.