Skip to content

Conversation

itowlson
Copy link
Collaborator

@itowlson itowlson commented Aug 27, 2025

Incomplete draft for discussion. This diverges from Till's draft SIP in some ways, mostly cosmetic and open to change; but also somewhat in preferring to constrain variation between profiles.

Example:

[component.build-profile-test]
source = "target/wasm32-wasip1/release/build_profile_test.wasm"
profile.debug.source = "target/wasm32-wasip1/debug/build_profile_test.wasm"
allowed_outbound_hosts = []
[component.build-profile-test.build]
command = "cargo build --target wasm32-wasip1 --release"
profile.debug.command = "cargo build --target wasm32-wasip1"
watch = ["src/**/*.rs", "Cargo.toml"]

This proposal uses a partial approach to the possible "am I running the same profile I built" problem. When you do a build, it records the built profile in a "last profile built" file. When you do a run, it checks if the profile being run matches the last built one, and prints a warning if not. This is certainly far from reliable: if you build both debug and release profiles, and then run both of them, you'll get a spurious warning.

If we're okay with this as a basis for further development, we need to look at what other fields should be allowed to vary by profile, e.g.:

  • allowed_outbound_hosts - you should be able to specify additional hosts. I'd be inclined not to say you can specify an entirely separate collection, because the 90% case is going to "I need to do sockets to a debugger." (Things like "I want to talk to the dev database not the prod database" should be handled by variables.)
  • dependencies - should be able to replace a dependency, e.g. to use its debug build or a stub/mock. If I squint I can imagine use cases for extra dependencies, in case a component has debug-only imports, not sure
  • environment - should be able to replace an EV or set additional EVs
  • KV/SQLite/LLM - my inclination that varying these by profile is probably an anti-pattern but I am open to being talked round if someone has a concrete use case - otherwise propose deferring to later
  • variables - not clear why you would, I guess there could be a knob to control profile-specific behaviour? Propose defer
  • files - not clear why you would, but I guess I could imagine a special build needing some additional asset? Again my inclination would be to defer until someone needs it

Possible further features:

  • whole components being conditional on the profile - e.g. include KV explorer only in certain build configs
  • this implies conditional triggers and I am not sure how much I love where this is going

Anyway here it is for discussion, please be gentle with me

@lann
Copy link
Collaborator

lann commented Aug 27, 2025

This diverges from Till's draft SIP in some ways, mostly cosmetic and open to change; but also somewhat in preferring to constrain variation between profiles.

I think I prefer the SIP's TOML structure with everything for component X / profile Y going under component.X.profile.Y. I agree that we should constrain variation between profiles regardless of the structure.

@lann
Copy link
Collaborator

lann commented Aug 27, 2025

I need to do sockets to a debugger.

I think we should do this as a separate feature: #3153

@itowlson
Copy link
Collaborator Author

itowlson commented Sep 1, 2025

Updated with reworked manifest:

[component.build-profile-test]
source = "target/wasm32-wasip1/release/build_profile_test.wasm"
allowed_outbound_hosts = []
[component.build-profile-test.build]
command = "cargo build --target wasm32-wasip1 --release"
watch = ["src/**/*.rs", "Cargo.toml"]
[component.build-profile-test.profile.debug]
source = "target/wasm32-wasip1/debug/build_profile_test.wasm"
build.command = "cargo build --target wasm32-wasip1"

I dislike the verbosity and repetition of the way TOML does this. It takes a lot to make me yearn for JSON but man this comes close. But the clarify benefit of the grouping overrides the verbosity issue.

(again, will do squashes once we have agreement on the approach)

@itowlson
Copy link
Collaborator Author

itowlson commented Sep 2, 2025

Done env vars and deps, holding off on allowed hosts: if we can do the special-case thing for debug connections, then I reckon we can defer allowed hosts in general until someone comes up with a use case.

Signed-off-by: itowlson <[email protected]>
@itowlson itowlson marked this pull request as ready for review September 3, 2025 00:12
command: super::common::Commands,
}

impl Component {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This brings to mind a famous quote, by Abraham Lincoln I believe...

#deep-inside-joke

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes: the trouble is that we've already rather violated President Lincoln's decree. We use serialisation types throughout Spin's application logic, and now the choice is major rework of multiple subsystems for no functional benefit, or papering over where we've coupled to a serialisation format that no longer gives us the correctness guarantees we seek. Making dangerous fields as private as possible and providing safer accessors seems like the lowest risk...

I did explore keeping Component as POD and doing something at the application level so that the components collection returned pre-profiled components, which would avoid a lot of this nonsense in favour of a single piece of once-and-for-all nonsense. It didn't really seem to work out, but I can revisit it if you feel that's a better strategy.

There, that will teach you to make light inside jokes.

Copy link
Collaborator

Choose a reason for hiding this comment

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

It didn't really seem to work out, but I can revisit it if you feel that's a better strategy.

Speak of the devil: https://github.com/spinframework/spin/pull/3246/files/ea595fcfd5df993eb55155409fb56eaf37f4d715#r2320229292

Copy link
Collaborator

@lann lann Sep 3, 2025

Choose a reason for hiding this comment

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

Another "I wonder if it would be better" here:

Would it be reasonable to handle profiles in a new normalize_manifest pass (i.e. normalize_manifest(manifest, profile))? It would have the benefit and/or fatal flaw of hiding most of the profile logic from the rest of the downstream code.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I explored this but had trouble getting it to work safely. This may point to a deeper problem of normalisation not being sufficiently embedded in the loader logic, but again this is a risk of world+dog being able to go "eh I'll just deserialise from TOML." The loader pipeline goes from TOML to LockedApp but there are things in the dev tooling that care about AppManifests and they tend to bypass the correct load sequence because it's not readily accessible. But like I say this may be an opportunity to improve the load sequence and make better guarantees, it will just likely be more work.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Could you say more about the troubles here? I can see a few potential problems along those lines but it isn't clear to me where things would be worse by normalizing in spin-manifest rather than spin-loader.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

If I remember rightly, the trouble was that some places were deserialising manifests rather than asking a loader to do it for them (because the loader produced a LockedApp and they wanted a Manifest). And this is hard to stop because deserialisability is a public feature. You need to make the DTO private and force consumers to go through a loader which can then enforce normalisation. (But some things do have a legit interest in the raw manifest. So, choices, choices.)

Let me look again. I didn't spend much time on it and my memory of what I was trying is not great.

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.

2 participants