Work on this exercise locally

This web app is a reference guide — you can read instructions, browse starter code, and view tests here. To actually complete the exercise, you need to work in your local development environment.

1Clone the repo: git clone https://github.com/weihaoqu/program-analysis-bootcamp-student
2Edit the starter file in your editor (VS Code, Vim, etc.) — replace failwith "TODO" with your implementation.
3Run the tests: dune runtest modules/module6-tools-integration/exercises/configurable-pipeline

Configurable Pipeline

5. Exercise 4: Configurable Pipeline (18 tests)

Goal: Build a configuration-driven pipeline that selects analysis passes and filters results by severity, category, and count.

Time: ~25 minutes

File to edit: exercises/configurable-pipeline/starter/pipeline.ml

Also provided (do not edit):

  • pass_registry.ml -- complete working implementations of safety_pass, taint_pass, and dead_code_pass
  • sign_domain.ml, taint_domain.ml -- abstract domains
  • finding_types.ml -- unified finding types
  • sample_programs.ml -- test programs

Dependencies: abstract_domains, shared_ast

Important: default_config crashes immediately

Unlike other exercises where failwith "TODO" only triggers when tests call the function, default_config is a module-level value (not a function). This means it is evaluated when the module loads, which happens before any tests run. As a result, the starter output is:

Fatal error: exception Failure("TODO: default_config")

Implement default_config first to unblock all 18 tests.

Types provided (not a TODO)

type pass_id = DeadCode | Safety | Taint

type pipeline_config = {
  enabled_passes : pass_id list;
  min_severity : Finding_types.severity;
  max_findings : int option;           (* None = no cap *)
  target_categories : Finding_types.category list option;  (* None = all *)
}

What to implement (in order)

#FunctionHint
1default_configAll passes enabled [DeadCode; Safety; Taint], min_severity = Info, max_findings = None, target_categories = None
2config_with_passes passesStart from default_config, override enabled_passes
3config_with_severity sev configReturn { config with min_severity = sev }
4config_with_max n configReturn { config with max_findings = Some n }
5config_with_categories cats configReturn { config with target_categories = Some cats }
6create_pass pidMap DeadCode -> Pass_registry.dead_code_pass, Safety -> Pass_registry.safety_pass, Taint -> Pass_registry.taint_pass
7build_pipeline configList.map create_pass config.enabled_passes
8apply_filters config findingsFour steps in order: (1) filter by min_severity, (2) filter by target_categories if Some, (3) sort by severity (highest first), (4) take first max_findings if Some
9run_pipeline config progBuild the pipeline, run all passes (concatenating findings), then apply filters

Run tests

dune runtest modules/module6-tools-integration/exercises/configurable-pipeline/

Starter output (crashes before tests run):

Fatal error: exception Failure("TODO: default_config")

Hints:

  • For apply_filters, use List.filteri or a helper to take the first N elements when capping at max_findings.
  • The severity filter keeps findings where Finding_types.severity_to_int f.severity >= Finding_types.severity_to_int min_severity.
  • The sort puts the highest severity first (descending order).