Skip to content

feat: support build backend secrets#6101

Merged
baszalmstra merged 11 commits into
mainfrom
claude/add-build-backend-secrets-QbCHd
May 13, 2026
Merged

feat: support build backend secrets#6101
baszalmstra merged 11 commits into
mainfrom
claude/add-build-backend-secrets-QbCHd

Conversation

@wolfv
Copy link
Copy Markdown
Member

@wolfv wolfv commented May 12, 2026

Description

Adds a secrets list to [package.build] so manifests can declare environment variables that should be exposed to the build script as secrets, mirroring rattler-build's build.script.secrets.

[package.build]
backend = { name = "pixi-build-rust", version = "*" }
secrets = ["CARGO_REGISTRY_TOKEN", "SCCACHE_BUCKET"]

Motivation: in the rattler-build recipe execution we restrict env access by default. This gives package authors a way to opt specific env vars through, without putting secret values in the manifest. Useful for credentials such as GH_TOKEN, registry tokens, sccache config, etc.

How Has This Been Tested?

Snapshots updated and TOML parsing tests added.

AI Disclosure

  • This PR contains AI-generated content.
    • I have tested any AI-generated content in my PR.
    • I take responsibility for any AI-generated content in my PR.

Tools: Claude (Claude Code)

Checklist:

  • I have performed a self-review of my own code
  • I have made corresponding changes to the documentation
  • I have added sufficient tests to cover my changes.

claude added 3 commits May 12, 2026 19:38
Add a `secrets` list to `[package.build]` so the manifest can declare
environment variables that should be exposed to the build script as
secrets. Names flow from the manifest into the `ProjectModel` sent to
the build backend; the intermediate backend then merges them into the
generated recipe's `build.script.secrets`, where rattler-build performs
the host-environment passthrough at build time.

Only names cross the wire — values are looked up by rattler-build from
the host environment during the build, so no secret material is
serialized in protocol messages or build records.

Example:

    [package.build]
    backend = { name = "pixi-build-rust", version = "*" }
    secrets = ["CARGO_REGISTRY_TOKEN", "SCCACHE_BUCKET"]
@wolfv
Copy link
Copy Markdown
Member Author

wolfv commented May 13, 2026

@ruben-arts thoughts? This came from Wintermute having issues using gh inside the build as we restricted the env access in rattler-build recipe execution.

@ruben-arts
Copy link
Copy Markdown
Contributor

If it works the same as rattler-build I'm all for it!

@wolfv
Copy link
Copy Markdown
Member Author

wolfv commented May 13, 2026

Yeah teh biggest question is where to put the config in the [package] toml.

Comment on lines +63 to +69
fn merge_project_secrets(script_secrets: &mut Vec<String>, project_secrets: &[String]) {
for name in project_secrets {
if !script_secrets.iter().any(|existing| existing == name) {
script_secrets.push(name.clone());
}
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont think this is correct. The secrets are part of the project model, so the backend should have added the secrets when generating the initial recipe.

Comment thread crates/pixi_build_types/src/project_model.rs Outdated

let build_string_prefix = th.optional("build-string-prefix");
let build_number = th.optional("build-number");
let secrets: Vec<String> = th.optional("secrets").unwrap_or_default();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont think this type annotation is needed, is it?

Comment thread crates/pixi_manifest/src/toml/build_backend.rs Outdated
Comment thread crates/pixi_manifest/src/build_system.rs Outdated
Copy link
Copy Markdown
Contributor

@baszalmstra baszalmstra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also update the schema (model.py) and the documentation?

@baszalmstra
Copy link
Copy Markdown
Contributor

Please also use the PR template from the repository.

@wolfv
Copy link
Copy Markdown
Member Author

wolfv commented May 13, 2026

I am fine with the comments but for me the main question is whether that is the right place to put the secrets key in the pixi.toml. Do you have an opinion on that?

claude and others added 4 commits May 13, 2026 08:07
- switch ProjectModel.secrets and PackageBuild.secrets from Vec to BTreeSet
  so order changes don't invalidate caches (baszalmstra)
- move secrets injection into individual backends; each generate_recipe impl
  now calls .with_secrets(model.secrets...) directly instead of having the
  intermediate backend post-process the recipe (baszalmstra)
- drop redundant test_secrets_default_empty
- add IsDefault impl for BTreeSet to support the field in stable hashing
- document secrets under [package.build] in pixi_manifest.md and schema/model.py

https://claude.ai/code/session_015JhTEMr2bEMaK4iSEiWbjj
@wolfv wolfv requested a review from baszalmstra May 13, 2026 11:21
@GuillaumeQuenneville
Copy link
Copy Markdown

I am fine with the comments but for me the main question is whether that is the right place to put the secrets key in the pixi.toml. Do you have an opinion on that?

It would be nice to have it at the workspace level also so we don't have to repeat for every package in a monorepo.

@wolfv
Copy link
Copy Markdown
Member Author

wolfv commented May 13, 2026

That goes a bit against the isolation of the package though, and "depending on what you need" ...

@GuillaumeQuenneville
Copy link
Copy Markdown

GuillaumeQuenneville commented May 13, 2026

That's a fair point. I see it similar to workspace dependencies proposal from bas (on my phone sorry will link in an edit).

Maybe a {workspace = true} syntax similar to the proposal?

@GuillaumeQuenneville
Copy link
Copy Markdown

GuillaumeQuenneville commented May 13, 2026

Longer version not from my phone.

I think the isolation is a great idea. The main point being security. My monorepo includes packaging for third_party packages we had to patch. We could reasonably get supply chain hacked and have our secret environment variables exposed since most build systems can execute arbitrary code. So we definitely should not do the default "passthru to all" approach. However, we could consider an explicit one.

There is this proposal from @baszalmstra which will add the [workspace.dependencies] table. #5945 which will add to the list of fields that packages can inherit from the workspace.

I think in the interest of consistency. I think it would be a good idea to allow a

[package.build]
secret = ["MYBLAH", {workspace = true}]

so that the general concept of "packages can inherit from the workspace" isn't too arbitrary decided per field.

That being said I also see the justification for only allowing package specific secrets and making this an exception. Since broadly sending build secrets to all packages build systems sounds like a code smell at face value. And the maintenance burden isn't very high.

Comment thread crates/pixi_build_rust/src/main.rs Outdated
Comment on lines +191 to +193
.collect::<std::collections::BTreeSet<_>>()
.into_iter()
.collect();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Collecting twice seems unnecesary

let build_string_prefix = th.optional("build-string-prefix");
let build_number = th.optional("build-number");
let secrets = th
.optional::<Vec<String>>("secrets")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cant we just use BTreeSet here? Instead of collecting twice?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried optional::<BTreeSet<String>>(...) but BTreeSet doesn't implement toml_span::Deserialize (only Vec, IndexSet via the local TomlIndexSet, etc.), so the workspace fails to compile. Reverted to parsing as Vec<String> and collecting once into the field's BTreeSet. Happy to add a TomlBTreeSet wrapper in pixi_toml if you'd prefer that route.


Generated by Claude Code

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I want that. Its nonsense to collect twice.

@wolfv
Copy link
Copy Markdown
Member Author

wolfv commented May 13, 2026

I could see secrets = { workspace = true } or your "extend list" syntax working, but needs some more design thought.

Alternatively, we could also add a flag to disable the isolation globally (we have the settings in rattler-build).

Passing through secrets like this is probably the cleanest option though.

@baszalmstra baszalmstra merged commit 488c883 into main May 13, 2026
41 checks passed
@baszalmstra baszalmstra deleted the claude/add-build-backend-secrets-QbCHd branch May 13, 2026 14:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants