Skip to content

workflow-embedded-program

DevOps execution block embeds program logic

Why

Programs embedded in deployment and build configuration bypass the normal language lint, type and local test boundaries. Simple sequences of existing commands are orchestration; executable logic belongs under the normal language tooling.

Fix

Reuse existing native commands or workflow steps. Keep control flow and inline interpreter source in maintained, linted repository code; avoid wrapper scripts solely to rearrange commands.

Examples

Before — flagged An argument after Bash -s is data, while stdin supplies the program
.github/workflows/ci.yml
jobs:
build:
steps:
- run: |
bash -s fixture-data <<'SOURCE'
printf fixture
SOURCE
After — preferred The script operand selects an external Bash program
.github/workflows/ci.yml
jobs:
build:
steps:
- run: bash scripts/check.sh fixture-data
Before — flagged An enabled healthcheck runs its shell program
compose.yaml
services:
app:
image: fixture
healthcheck:
disable: false
test: [CMD-SHELL, "printf first && printf second"]
After — preferred A disabled healthcheck retains inert command data
compose.yaml
services:
app:
image: fixture
healthcheck:
disable: "true"
test: [CMD-SHELL, "printf first && printf second"]
Before — flagged A target variable selects inline interpreter source
Makefile
CMD = python3 scripts/check.py
all: CMD = python3 -c 'print(1)'
all:
@$(CMD)
After — preferred A target variable selects the maintained external script
Makefile
CMD = python3 -c 'print(1)'
all: CMD = python3 scripts/check.py
all:
@$(CMD)
Before — flagged An executable mise task retains its own source location
mise.toml
[vars]
text = '''
run = "printf inert; printf data"
'''
[tasks.probe]
"run" = "printf first && printf second"
After — preferred Literal command-shaped data does not become a mise task
mise.toml
[vars]
text = '''
run = "printf inert; printf data"
'''
[tasks.probe]
"run" = "printf public-marker"
Before — flagged A later invocation still rejects inline interpreter source
.github/workflows/ci.yml
jobs:
test:
steps:
- run: |
uv run ruff check .
python3 -c 'print(1)'
After — preferred Run existing tools directly without a wrapper script
.github/workflows/ci.yml
jobs:
test:
steps:
- run: |
uv run ruff check .
uv run pytest
Before — flagged Keep procedural validation out of workflow YAML
.github/workflows/ci.yml
jobs:
test:
steps:
- run: |
for package in api worker; do
make test-package PACKAGE="$package"
done
After — preferred Invoke an external program with quoted arguments
.github/workflows/ci.yml
jobs:
test:
steps:
- run: |
MODE=test python3 scripts/check.py --target "$TARGET"

Files

**/*.{yaml,yml,toml}**/Dockerfile***/*.Dockerfile**/[Mm]akefile**/GNUmakefile