agentleFS
Microsoft AzureKnown publisherAzure/azure-guest-attestation-sdk/.github/copilot-instructions.md

azure-guest-attestation-sdk

Copilot instructions3 starsChanged 4 months agoMITView on GitHub

These instructions apply to every AI agent session working on this repository, regardless of platform (Linux, Windows, macOS) or context window state. Read this file in its entirety before making any changes. AI can produce code very fast, but bad code is more expensive than ever: a codebase that is hard to change is a codebase where AI compounds entropy on every iteration. Optimize for a codebase that is easy to change, easy to test, and easy to reason about.…

  • Where files are headingNew Copilot instructions files have more rules about branches and pull requests, and fewer about code style.

    Of the Copilot instructions files we read, the 2,336 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.

The file

Show its rules and text

We split this copilot-instructions.md into the rules it gives an agent

21 rules. About 0 are common, 16 are distinctive, and 5 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈16

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 5

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Do not jump straight to an implementation plan or to editing files.

    line 18
  2. Distinctive:

    Grill the user: ask targeted questions until you and the user share the same mental model of the change.

    line 21
  3. Distinctive:

    Do not invent requirements — surface ambiguity instead.

    line 24
  4. Distinctive:

    Only after the design concept is shared, propose a plan or a PRD.

    line 25
  5. Distinctive:

    Prefer this over eagerly creating planning artifacts.

    line 28
  6. Distinctive:

    Write or update a test that expresses the behavior (see §6).

    line 46
  7. Very specific:

    Run the relevant CI command from §2 (at minimum cargo fmt, cargo clippy --workspace --all-targets -- -D warnings, and the targeted cargo …

    line 48
  8. Very specific:

    If a behavior genuinely cannot be unit-tested (see §10), say so explicitly and prefer an injectorpp mock or a vtpm_tests-gated integration …

    line 53
  9. Distinctive:

    Avoid sprawling shallow modules (many small files each exposing many functions).

    line 59
  10. Distinctive:

    When you find related logic scattered across shallow helpers, consider consolidating it behind one interface rather than adding another …

    line 69
  11. Distinctive:

    Every change is an opportunity to leave the module slightly better designed than you found it.

    line 75
  12. Distinctive:

    Treat AI-generated edits as tactical: locally correct, globally unaware.

    line 83
  13. Distinctive:

    Every commit must pass all of the following before push.

    line 102
  14. Very specific:

    If you edit the hook, keep it in sync with §2.2 above.

    line 179
  15. Very specific:

    Run cargo fmt before committing.

    line 290
  16. Very specific:

    Use tracing::info! / tracing::debug!

    line 297
  17. Distinctive:

    Commit messages: concise summary line, blank line, bullet-point body.

    line 302
  18. Distinctive:

    Only stage files relevant to the current change.

    line 305
  19. Distinctive:

    Run these in order. All must pass:

    line 310
  20. Distinctive:

    If you have reference-TPM prerequisites (Perl, C toolchain):

    line 326
  21. Distinctive:

    If your context window was compacted and you lost history:

    line 352

≈ “Common” is an estimate: at least 1 in 5 of the 3,779 Copilot instructions files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
copilot-instructions.md

Copilot Agent Instructions — Azure Guest Attestation SDK

These instructions apply to every AI agent session working on this repository, regardless of platform (Linux, Windows, macOS) or context window state. Read this file in its entirety before making any changes.


0. Engineering Philosophy — Software Fundamentals Still Matter

AI can produce code very fast, but bad code is more expensive than ever: a codebase that is hard to change is a codebase where AI compounds entropy on every iteration. Optimize for a codebase that is easy to change, easy to test, and easy to reason about. The rules below apply to every task.

0.1 Reach a shared design concept before writing code

Do not jump straight to an implementation plan or to editing files. When the user gives you a non-trivial task:

  1. Grill the user: ask targeted questions until you and the user share the same mental model of the change. Walk down each branch of the design tree and resolve dependencies between decisions one at a time. Do not invent requirements — surface ambiguity instead.
  2. Only after the design concept is shared, propose a plan or a PRD. For small changes, go straight to a focused diff; for larger ones, write the plan into the relevant module's README or a scratch note first.
  3. Prefer this over eagerly creating planning artifacts. An asset created from a misaligned design concept is worse than no asset at all.

0.2 Use the project's ubiquitous language

This repo has a precise vocabulary: Tpm, AttestationClient, MaaProvider, ImdsClient, attest_guest, attest_platform, submit_tee_only, vtpm_tests, NV index, TEE report, SNP, TDX, MAA, IMDS, THIM, CoRIM, endorsement, quote, AK (attestation key), EK (endorsement key), etc. Use these exact terms in code, comments, commit messages, and when talking to the user. Do not invent synonyms. When introducing a new domain concept, name it once and reuse the name everywhere.

0.3 Take small, test-driven steps — do not outrun your headlights

The rate of feedback is your speed limit. Do not produce large diffs and then check them at the end. For each logical change:

  1. Write or update a test that expresses the behavior (see §6).
  2. Make the smallest change that makes the test pass.
  3. Run the relevant CI command from §2 (at minimum cargo fmt, cargo clippy --workspace --all-targets -- -D warnings, and the targeted cargo test).
  4. Refactor if needed, then move on.

If a behavior genuinely cannot be unit-tested (see §10), say so explicitly and prefer an injectorpp mock or a vtpm_tests-gated integration test before falling back to "manual only".

0.4 Prefer deep modules with simple interfaces

Avoid sprawling shallow modules (many small files each exposing many functions). Prefer a smaller number of deep modules: a simple, well-considered public interface hiding meaningful implementation complexity. When touching this codebase:

  • Design the interface carefully (names, types, error variants, invariants, doc comments). This is the part the rest of the system — and the AI on the next iteration — will see.
  • The implementation behind that interface can be denser; the interface is what protects the rest of the codebase from churn.
  • When you find related logic scattered across shallow helpers, consider consolidating it behind one interface rather than adding another helper.
  • Tests should target the module's public interface, not its internals.

0.5 Invest in the design of the system every day

Every change is an opportunity to leave the module slightly better designed than you found it. Do not "just make the change" if it visibly degrades the structure (duplicates a concept, leaks an internal type, widens an interface unnecessarily, breaks a layering rule). Call out the tension to the user and propose a small refactor instead.

0.6 You are the strategic layer

Treat AI-generated edits as tactical: locally correct, globally unaware. Your job is the strategic layer — module boundaries, interfaces, the ubiquitous language, the test strategy, MSRV and cross-platform constraints (§4), and the CI contract (§2). Never delegate those.


1. Repository Overview

ItemValue
LanguageRust (edition 2021)
MSRV1.90 — every change must compile on Rust 1.90
Workspace memberscrates/azure-tpm (TPM crate), crates/azure-guest-attestation-sdk (SDK), tools/azure-guest-attest (CLI), tools/azure-guest-attest-web (Web tool). crates/azure-tpm-testkit is excluded from the workspace (reference-TPM test harness, not published).
CI.github/workflows/ci.yml — runs on both ubuntu-latest and windows-latest
Pre-commit hook.githooks/pre-commit — must mirror CI flags exactly

2. CI Checks — The Single Source of Truth

Every commit must pass all of the following before push. These are the exact commands CI runs. Do not invent variations.

Path filtering: CI uses dorny/paths-filter to skip expensive jobs (clippy, test, vtpm-tests, msrv, docs, coverage) on PRs that only touch non-code files (markdown, scripts, etc.). Push to main always runs everything. The fmt job always runs. Code paths that trigger the full suite: crates/**, tools/**, Cargo.toml, Cargo.lock, rust-toolchain.toml, .github/workflows/ci.yml.

2.1 Format

cargo fmt --all -- --check

2.2 Clippy (runs on Linux AND Windows)

cargo clippy --workspace --all-targets -- -D warnings

Critical: Do NOT use --all-features. CI does not pass --all-features to clippy. The reference-TPM harness (activated with --cfg vtpm_tests) pulls ms-tpm-20-ref (vendored OpenSSL) which requires Perl and a C toolchain; enabling it here will fail on runners that lack those.

2.3 Unit tests — no vTPM (runs on Linux AND Windows)

cargo test --workspace

No --features, no --test-threads=1. Tests must be safe to run in parallel across threads.

2.4 vTPM integration tests (runs on Linux AND Windows)

RUSTFLAGS="--cfg vtpm_tests" cargo nextest run -p azure-guest-attestation-sdk

The reference-TPM harness is activated by the custom --cfg vtpm_tests flag (NOT a Cargo feature). It is pulled via cfg-gated dev-dependencies so the published crates never depend on ms-tpm-20-ref.

2.5 MSRV check (Linux only)

cargo +1.90 check --workspace

Dev-dependencies are excluded from cargo check, so newer crates like injectorpp are fine as long as the main code compiles on 1.90.

2.6 Docs

RUSTDOCFLAGS=-Dwarnings cargo doc --workspace --no-deps

2.7 Coverage (Linux only)

RUSTFLAGS="--cfg vtpm_tests" cargo llvm-cov --workspace \
  --ignore-filename-regex '(src/lib\.rs|azure-guest-attest/src/main\.rs)$' \
  --fail-under-lines 60

3. Pre-Commit Hook

The hook at .githooks/pre-commit must mirror the CI clippy flags:

cargo clippy --workspace --all-targets -- -D warnings

If you edit the hook, keep it in sync with §2.2 above. Never add --all-features to the hook.

4. Cross-Platform Rules

CI tests on both Linux and Windows. Every change must work on both.

RuleDetails
No Unix-only pathsUse std::path / std::env::consts::OS — never hardcode /dev/... outside #[cfg(unix)]
No Unix-only APIsio::Error::other() requires Rust ≥ 1.74 — OK for MSRV 1.90
Windows #[cfg]Windows-specific code must be gated with #[cfg(target_os = "windows")]
Line endingsThe repo uses LF (.gitattributes). Don't introduce CRLF.
Dev-dependenciesMust compile on all CI platforms (Linux + Windows). If a dev-dep is platform-specific, gate its usage with #[cfg(...)]

5. Reference-TPM Harness (--cfg vtpm_tests)

The in-process reference TPM is not a Cargo feature — it is activated by a custom --cfg vtpm_tests compile flag, set via RUSTFLAGS. This keeps the heavy git-sourced ms-tpm-20-ref (vendored OpenSSL, needs Perl + a C toolchain) out of the default build graph and out of the published crates (git dependencies cannot be published to crates.io).

ConfigPurposeHow
--cfg vtpm_testsReference-TPM testsazure-tpm uses a cfg-gated dev-dependency on ms-tpm-20-ref + an in-crate harness (Tpm::open_reference_for_tests()). The SDK uses the non-published azure-tpm-testkit crate (azure_tpm_testkit::reference_tpm()). Gate test code with #[cfg(vtpm_tests)].
(none / default)Normal SDK functionalityCI clippy + unit tests run without the flag.

Why not a Cargo feature? Features cannot gate dev-dependencies, and a git dependency (even optional/feature-gated) blocks cargo publish. A --cfg toggling a [target.'cfg(vtpm_tests)'.dev-dependencies] table is the only mechanism that keeps the heavy dep out of the default graph, out of the published manifest, AND activates it on demand.

azure-tpm-testkit is deliberately excluded from the workspace (see root Cargo.toml exclude) so cargo build/clippy/test --workspace never pulls ms-tpm-20-ref. It is compiled only as a cfg-gated dev-dependency of the SDK. The unexpected_cfgs lint is satisfied by the [workspace.lints.rust] check-cfg declaration (opt in per-crate with [lints] workspace = true).

Key invariant: cargo clippy --workspace --all-targets and cargo test --workspace (without the flag) must succeed and must NOT compile ms-tpm-20-ref. All test code that needs the reference TPM must be gated with #[cfg(vtpm_tests)].

6. Testing Conventions

6.1 Test naming

  • Pure unit tests: descriptive name (parse_version_pair_major_minor)
  • vTPM integration tests: prefix vtpm_ and gate with #[cfg(vtpm_tests)]
  • Injectorpp (mocked) tests: no special prefix; use unsafe { ... } blocks for _unchecked API

6.2 Injectorpp (runtime mocking)

The SDK uses injectorpp (dev-dependency) for runtime function mocking.

Required workspace settings (already in root Cargo.toml):

[profile.test]
opt-level = 0
debug = true
lto = false
codegen-units = 1
incremental = false

API pattern (use the unchecked API for methods with complex signatures):

fn fake_some_method(_self: &SomeStruct, _arg: &str) -> io::Result<Vec<u8>> {
    Ok(b"mocked".to_vec())
}

#[test]
fn test_with_mock() {
    use injectorpp::interface::injector::*;
    let mut injector = InjectorPP::new();
    unsafe {
        injector
            .when_called_unchecked(injectorpp::func_unchecked!(SomeStruct::method))
            .will_execute_raw_unchecked(injectorpp::func_unchecked!(fake_some_method));
    }
    // ... test code that exercises the mocked path ...
}

Rules:

  • Fake functions must be declared as standalone fn items (not closures) with the exact same signature as the target method (including &self as first param).
  • The injector variable must stay alive (not dropped) for the duration of the test — dropping it restores the original function.
  • injectorpp patches process-global memory, so tests that mock the same function must not run in parallel. cargo test may interleave them; cargo nextest gives each test its own process.
  • injectorpp supports Linux, macOS, and Windows.

6.3 Thread safety

CI runs cargo test --workspace without --test-threads=1. Tests must be safe to run in parallel unless they use injectorpp to mock the same function, in which case the mocking scope should be as narrow as possible.

6.4 NV index ranges

vTPM tests that write NV indices must use distinct index values to avoid collisions when sharing a reference TPM instance (e.g. 0x0150_XXXX).

7. Code Style

  • Run cargo fmt before committing.
  • License header on every .rs file:
    // Copyright (c) Microsoft Corporation.
    // Licensed under the MIT License.
  • Rustdoc comments on all public items.
  • Use tracing::info! / tracing::debug! (not println!) for diagnostics.

8. Git Workflow

  • Each task gets its own branch (e.g. snp_fix, injector, test_coverage).
  • Commit messages: concise summary line, blank line, bullet-point body.
  • The pre-commit hook runs fmt + clippy automatically. If the hook fails, fix the issues before committing — do not bypass it.
  • Only stage files relevant to the current change. Do not stage unrelated files, coverage artifacts, embedded git repos, etc.

9. Verifying Before Push — Checklist

Run these in order. All must pass:

# 1. Format
cargo fmt --all -- --check

# 2. Clippy (matches CI exactly)
cargo clippy --workspace --all-targets -- -D warnings

# 3. Unit tests (no features, parallel)
cargo test --workspace

# 4. MSRV (if Rust 1.90 toolchain is installed)
cargo +1.90 check --workspace

If you have reference-TPM prerequisites (Perl, C toolchain):

# 5. vTPM tests
RUSTFLAGS="--cfg vtpm_tests" cargo nextest run -p azure-guest-attestation-sdk

10. What Cannot Be Unit-Tested

Some code paths require real hardware or network and cannot be covered by unit tests or injectorpp mocking:

CategoryReason
Tpm::open()Needs /dev/tpmrm0 or Windows TBS
AttestationClient::attest_guest() / attest_platform()Needs Tpm instance (private inner)
ImdsClient HTTP body parsingreqwest::Response has no public constructor
MaaProvider::attest_guest() / submit_tee_only()Creates reqwest::Client internally
Windows #[cfg] blocks on Linux CIStructurally unreachable

These are covered by:

  • the --cfg vtpm_tests reference-TPM harness
  • Manual testing on real CVM hardware
  • Integration test environments

11. Resuming After Context Compaction

If your context window was compacted and you lost history:

  1. Read this file first — it contains all the rules.
  2. Read .github/workflows/ci.yml — it is the ground truth for CI.
  3. Read .githooks/pre-commit — must match CI clippy flags.
  4. Check git log --oneline -20 — understand recent changes.
  5. Check git branch — know which branch you're on.
  6. Never guess CI flags — look them up from ci.yml every time.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.