Trust Boundary Model for Loading Repository Configuration in no-mistakes: A Security Deep Dive

no-mistakes implements a fail-closed trust boundary that exclusively loads executable repository configuration from the repository's default branch, ensuring malicious pull requests cannot inject arbitrary commands unless explicitly authorized by allow_repo_commands in the trusted copy.

The kunchenguid/no-mistakes repository addresses a critical security challenge in CI/CD pipelines: preventing contributors from executing arbitrary code through manipulated configuration files. By establishing a strict trust boundary model for loading repository configuration, the system guarantees that only approved, default-branch settings can influence code execution decisions.

How the Trust Boundary Works in no-mistakes

The architecture treats configuration from the default branch as the sole source of truth for security-sensitive settings, while isolating potentially untrusted contributions.

Trusted Default-Branch Configuration

The daemon always fetches the default branch of the remote repository to locate the .no-mistakes.yaml file. This copy is designated as the trusted repo config and is never sourced from the SHA that a contributor just pushed.

In internal/daemon/manager.go, the daemon attempts to load this trusted configuration during startup. If the file exists and parses correctly, it becomes the authoritative source for determining what commands may run. This behavior prevents a malicious actor from opening a pull request that modifies .no-mistakes.yaml to execute harmful scripts.

The EffectiveRepoConfig Merge Strategy

The EffectiveRepoConfig function in internal/config/config.go orchestrates the configuration merge according to the following hierarchy:

  1. Global configuration (~/.no-mistakes/config.yaml) provides baseline settings
  2. Trusted repo configuration (default branch) supplies security-sensitive fields
  3. Pushed branch configuration contributes only non-executing fields (such as ignore_patterns) when explicitly permitted

The merge order ensures that executable directives from a contributor's branch are ignored unless the trusted configuration explicitly enables them.

Security Controls and Configuration Fields

The trust boundary divides configuration fields into protected categories, with specific gates controlling access to code execution capabilities.

The allow_repo_commands Gate

The boolean field allow_repo_commands serves as the primary security switch. When set to false (the default) in the trusted configuration, the system ignores all commands.{test,lint,format} and agent fields from the pushed branch.

Only when allow_repo_commands is explicitly true in the default-branch copy does the pipeline consider executable commands from the contributor's configuration. This design ensures that repository maintainers must opt-in to command execution capabilities, preventing accidental exposure to arbitrary code execution.

Protected vs. Unprotected Fields

The trust boundary model applies different rules based on field sensitivity:

  • Protected fields (default-branch only): commands, agent, document.instructions
  • Unprotected fields (may merge from pushed branch): ignore_patterns

Documentation placement policies and instruction sets are also read exclusively from the trusted copy, preventing contributors from weakening safety policies or documentation requirements.

Fail-Closed Design and Error Handling

The system implements a failure-closed security posture. If loading the trusted configuration fails due to parsing errors, missing files, or fetch failures, the daemon logs a warning and proceeds with an empty configuration.

This empty configuration effectively disables all command execution and agent selection for that run. As implemented in internal/config/config.go, the code explicitly returns an empty RepoConfig struct when the trusted source is unavailable, ensuring that malformed or malicious configurations cannot cause the pipeline to execute unsafe commands.

Implementation in Source Code

The trust boundary logic resides primarily in internal/config/config.go, with integration points in internal/daemon/manager.go.

Loading the effective configuration follows this pattern:

func LoadEffectiveConfig(ctx context.Context, repoRoot string) (*config.Config, error) {
    // 1. Load global config (~/.no-mistakes/config.yaml)
    global, err := config.LoadGlobal()
    if err != nil { return nil, err }

    // 2. Load the trusted repo config from the default branch
    trustedRepo, err := config.LoadRepoFromDefaultBranch(ctx, repoRoot)
    if err != nil {
        slog.Warn("trusted repo config parse failed; commands/agent disabled", "err", err)
        trustedRepo = &config.RepoConfig{} // empty – disables exec fields
    }

    // 3. Merge into a single Config object
    cfg := config.Merge(global, trustedRepo)
    return cfg, nil
}

When executing pipeline steps, the system checks the trust boundary before invoking commands:

func runLintStep(cfg *config.Config, workdir string) error {
    // The command comes from cfg.Commands.Lint, which is only populated
    // when allow_repo_commands is true in the trusted config.
    if cfg.Commands.Lint == "" {
        return fmt.Errorf("lint command disabled: not trusted")
    }
    return exec.CommandContext(ctx, "sh", "-c", cfg.Commands.Lint).Run()
}

The implementation is validated by regression tests in internal/config/config_repo_trust_test.go and end-to-end tests in internal/e2e/harness.go, which verify that commands remain disabled when the trusted configuration is unavailable or when allow_repo_commands is false.

Summary

  • Default-branch authority: no-mistakes reads security-sensitive configuration exclusively from the repository's default branch, never from pull request branches.
  • allow_repo_commands gating: Executable fields require explicit opt-in via a boolean flag in the trusted configuration.
  • Fail-closed behavior: Configuration parsing failures result in empty, safe defaults that disable all command execution.
  • Layered validation: The EffectiveRepoConfig function enforces the trust boundary by merging global, trusted, and (conditionally) pushed configurations.
  • Test coverage: Comprehensive unit and e2e tests in internal/config/config_repo_trust_test.go verify the trust boundary implementation.

Frequently Asked Questions

What happens if the trusted configuration file is missing from the default branch?

The daemon logs a warning and proceeds with an empty RepoConfig struct. This fail-closed design ensures that all commands and agent fields remain disabled, preventing the execution of any commands that might be specified in an untrusted pull request.

Can contributors override commands in their pull requests?

Contributors cannot override commands unless the repository's default-branch .no-mistakes.yaml explicitly sets allow_repo_commands: true. When this flag is false (the default), the system ignores all command definitions from the pushed branch, reading only non-executable fields like ignore_patterns.

How does no-mistakes prevent command injection through configuration?

By reading executable fields (commands.test, commands.lint, commands.format, and agent) exclusively from the default branch, the system ensures that only repository maintainers can authorize code execution. Even if a contributor modifies .no-mistakes.yaml in their pull request, those changes are filtered out by the EffectiveRepoConfig merge logic unless explicitly permitted by the trusted configuration.

Where is the trust boundary logic tested?

The trust boundary is validated in internal/config/config_repo_trust_test.go through unit tests like TestLoadTrustedRepoConfig_FailClosedOnFetchFailure and TestEffectiveRepoConfig. Additionally, end-to-end tests in internal/e2e/harness.go verify that the daemon correctly disables commands when loading untrusted configurations.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →