Skip to main content
Expand Labs

Open source · Apache-2.0

Cloud sovereignty assessment for EU and Ontario public procurement

level-assessor checks cloud deployments against the assurance levels in the EU's proposed Cloud and AI Development Act, and suppliers against Ontario's Buy Ontario Procurement Directive. It tells you the level you can defend, the exact dependency that caps it, and the evidence you still need — citing the rule behind every result.

Rule set 0.1.0 · Updated September 26, 2026

Two jurisdictions, one method

A supplier selling cloud services to governments on both sides of the Atlantic can run both checks against the same offering. In each, the legal thresholds live in sourced, versioned rules rather than in code.

European Union

Cloud and AI Development Act (CADA) — proposed

Question it answers
Which Union assurance level (1–4) can this cloud deployment defend, and which dependency caps it?
What you give it
A Terraform plan or state, a short YAML questionnaire, or both.
level-assessor assess plan.json
CADA assurance levels explained

Canada — Ontario

Buy Ontario Procurement Directive — in force 13 April 2026

Question it answers
Is this supplier a "US business" excluded from Ontario public procurement, and does an exception apply?
What you give it
Three facts: headquarters country, full-time staff in Canada, and share of delivery from Canada.
level-assessor buy-ontario --hq-country US --canadian-fte 180 --delivery-in-canada 95
Buy Ontario test and checker

Why a provider's marketing page can't tell you your level

Your assurance level depends on every service the deployment relies on. The one that limits it is usually small — a CDN, a DNS zone, an identity provider or a log sink — and rarely the compute.

In this example the workload runs on Scaleway, an EU provider, but the site sits behind a US CDN and US DNS. That caps the deployment at Level 2. Replace the CDN and DNS, and Level 3 becomes available.

Output trimmed. The plan is a synthetic test fixture from the repository.

$ level-assessor assess plan.json

╭─ Highest defensible level ──────────────────────────────────╮
│ Union assurance level 2                                     │
│ No criterion fails at this level, but 45 could not be       │
│ determined from the input.                                  │
╰─────────────────────────────────────────────────────────────╯

What caps it at level 3
  ✗ cada.annex2.l3.g CADA Annex II, point 3.1(g)
    Amazon Web Services is subject to the control of US, through
    Amazon.com, Inc., and US is not an associated third country
    under Article 18. Level 3 is not available for this dependency.
    brought in by aws_cloudfront_distribution.site
  ✗ cada.annex2.l3.g CADA Annex II, point 3.1(g)
    Cloudflare is subject to the control of US, through Cloudflare, Inc.
    brought in by cloudflare_record.www, cloudflare_zone.example

Evidence to obtain (45 criteria)
  ? cada.annex2.l1.a Amazon Web Services — Provider established in the Union
  ? cada.annex2.l1.c Scaleway — Customer data, metadata and telemetry remain in the Union
  … and 39 more. Use --format md for the full list.
An EU-hosted deployment capped at Level 2 by its CDN and DNS providers.

What an EU assessment gives you

  1. 1

    The highest defensible level

    The highest CADA assurance level, from 1 to 4, at which no criterion fails — and separately, the level that is fully evidenced today.

  2. 2

    The resource that caps it

    Not "AWS is US-controlled", but aws_cloudfront_distribution.site puts a US-controlled provider in the delivery path — with the rule and source that say so.

  3. 3

    The evidence still to collect

    Every criterion infrastructure code can't answer, with the question to put to the supplier for each.

  4. 4

    An evidence pack for the file

    A Markdown or JSON report with a manifest of input hashes and rule set version that anyone can re-run and get the same result.

The two numbers are usually far apart, and the distance between them is the work outstanding. Reporting only the first would let a deployment with forty unanswered criteria be described as “Level 4”.

Who it's for

You are…You want to know…Start with
Public-sector buyer in an EU member stateDoes this bid meet the level our risk assessment requires, and what do I ask the supplier for?assess … --required-level 3 --format md
Cloud or platform engineer serving EU public bodiesWhich parts of our stack stop us reaching Level 3?assess plan.json
Cloud supplier or integrator bidding for EU contractsWhat can we honestly claim, and what evidence backs it up?assess plan.json -q answers.yaml
Ontario public-sector buyerIs this supplier a "US business", and can we still award under an exception?buy-ontario …
Supplier bidding in Ontario, including Canadian arms of US firmsWill we be excluded, and what would let us bid?buy-ontario …
Auditor or reviewer in either jurisdictionCan I reproduce the result on file?Re-run the command recorded in the report

How it works: from resource to jurisdiction

Each Terraform resource is traced to the service it uses, the provider behind that service, the entity that controls the provider, and the country that entity is established in. Annex II criteria are evaluated on providers; the resource is kept so the report can name what pulled a provider in.

  1. 1. Resource

    aws_cloudfront_distribution.site

  2. 2. Service

    Amazon CloudFront (CDN)

  3. 3. Provider

    Amazon Web Services

  4. 4. Controlling entity

    Amazon.com, Inc.

  5. 5. Jurisdiction

    United States

Minimum across the graph

A deployment is only as sovereign as its weakest required dependency. One provider failing a criterion caps the whole deployment.

Cumulative across levels

Under CADA Article 20(1), failing any criterion of a lower level precludes every higher level. See all 40 criteria by level.

Provider profiles in v0.1: Amazon Web Services (US), Microsoft Azure (US), Google Cloud Platform (US), Cloudflare (US), OVHcloud (FR), Scaleway (FR), STACKIT (DE). Anything else is reported as an unmapped provider.

Built to stand up in a procurement file

Every rule is sourced

Criteria live in versioned YAML, not code. Each carries a source URL, the exact article or annex point, the date a human last verified it, a status and a plain-English rationale. A rule missing any of them will not load.

Undetermined is not a pass

Every check returns pass, fail or undetermined. An evidence gap is never counted as compliance and never reported as a failure — it becomes a question in the evidence pack.

Every report is reproducible

The manifest records the sha256 of each input, the rule set version and hash, and the tool version. Same inputs and rules, same report — apart from the timestamp.

Nothing leaves your machine

No network telemetry. The browser UI listens on 127.0.0.1 only and loads nothing from the internet. Unmapped resources are reported, never silently dropped.

Annex II criteria encoded
40
Sourced rule assertions
148
Verified against primary text
101
Cloud provider profiles
7

Quick start

Requires Python 3.12. The package is not on PyPI yet, so install it from a checkout of the GitHub repository.

git clone https://github.com/ExpandLabs/level-assessor.git && cd level-assessor
uv tool install .            # or: pipx install .

# EU: export a Terraform plan and assess it
terraform show -json plan.tfplan > plan.json
level-assessor assess plan.json --required-level 3

# No Terraform? Describe the deployment in YAML instead
level-assessor assess --questionnaire my-deployment.yaml

# Ontario: check a supplier from three facts
level-assessor buy-ontario --hq-country US --canadian-fte 180 --delivery-in-canada 95

# Prefer clicking? Open the local browser UI
level-assessor ui plan.json

Exit code 0 means no failures and no gap against the required level; 1 means capped or excluded — so the same command can gate a CI pipeline.

Current limitations (v0.1)

  • Inputs are Terraform plan/state and YAML questionnaires. Live cloud-account scanning is not built yet.
  • Subcontractors are in the schema but not evaluated, so Annex II 1.1(f) appears as an evidence gap on every assessment.
  • Reports are not signed yet; the signing hook exists.
  • In Canada only Ontario's Buy Ontario Directive is covered — not federal rules or other provinces.
  • The rule set holds 148 sourced assertions: 101 verified, 35 contested and 12 draft, with 38 open TODO(verify) notes.

Frequently asked questions

What is level-assessor?

level-assessor is an open-source command-line tool from Expand Labs that checks cloud deployments and suppliers against public-sector sovereignty rules. For the EU it reports the highest Union assurance level (1–4) a deployment can defend under the proposed Cloud and AI Development Act. For Ontario it determines whether a supplier is a "US business" under the Buy Ontario Procurement Directive.

What input does the EU assessment need?

A Terraform plan or state exported as JSON with terraform show -json, a short YAML questionnaire, or both. The plan tells the tool which providers and regions the deployment depends on; the questionnaire supplies what infrastructure code cannot, such as where support staff are located.

Does the tool send my infrastructure data anywhere?

No. It runs locally. The only log it keeps is a local record of which rules fired, which you can turn off with --no-telemetry. The optional browser UI listens on 127.0.0.1 only and loads nothing from the internet.

Is the output legal advice?

No. The Cloud and AI Development Act is Commission proposal COM(2026) 502 of 3 June 2026 and is not adopted law. Every report says so and records the rule set version that produced it. The Buy Ontario rule is in force but its encoding cites a law firm's summary and is marked contested until checked against the Directive text.

What does "undetermined" mean in a report?

The input could not answer the question — for example, whether a provider's staff are Union citizens. Undetermined is never counted as a pass and never reported as a failure. It is an evidence gap, and the report lists the question to put to the supplier.

Which cloud providers does it recognise?

Version 0.1 profiles AWS, Microsoft Azure, Google Cloud, Cloudflare, OVHcloud, Scaleway and STACKIT. Any resource it cannot map is attributed to an "unknown" provider and listed in its own section of the report — never silently skipped.

Can the result be reproduced by an auditor?

Yes. Every report embeds a manifest with the sha256 of each input, the rule set version and hash, and the tool version. The same inputs and rules produce the same report, apart from the timestamp.

How much does it cost and what is the licence?

It is free and open source under the Apache-2.0 licence. It requires Python 3.12 and is installed from the GitHub repository.

Run it against your own deployment

level-assessor is free and open source under Apache-2.0. It runs on your machine, and every result cites the rule behind it. If you need help reaching the level your procurement requires, talk to us.