Skip to content

fix: resolve infinite recursion in Provisioner.Class(), Type(), and Description()#483

Merged
mathieu-benoit merged 2 commits into
score-spec:mainfrom
Siddhartha-singh01:fix/provisioner-infinite-recursion
May 16, 2026
Merged

fix: resolve infinite recursion in Provisioner.Class(), Type(), and Description()#483
mathieu-benoit merged 2 commits into
score-spec:mainfrom
Siddhartha-singh01:fix/provisioner-infinite-recursion

Conversation

@Siddhartha-singh01
Copy link
Copy Markdown
Contributor

Summary

Fixes #481

The Provisioner struct in internal/provisioners/envprov/envprov.go had three methods (Class(), Type(), Description()) that called themselves unconditionally, causing infinite recursion and a stack overflow crash whenever invoked.

Changes

internal/provisioners/envprov/envprov.go

  • Class() → returns "default" (consistent with the class checked in Match())
  • Type() → returns "environment" (consistent with the type checked in Match())
  • Description() → returns "" (consistent with envVarResourceTracker)

internal/provisioners/envprov/envprov_test.go

  • Added 3 unit tests (class returns default, type returns environment, description returns empty string) to verify correct behavior and prevent regressions.

Testing

All existing and new tests pass:

…escription()

The Provisioner struct in the envprov package had three methods (Class,
Type, Description) that called themselves unconditionally, causing a
stack overflow crash whenever invoked.

Replace recursive self-calls with correct static return values:
- Class() returns default (matches the class checked in Match())
- Type() returns environment (matches the type checked in Match())
- Description() returns empty string (consistent with envVarResourceTracker)

Add unit tests to verify the methods return expected values and prevent
future regressions.

Fixes score-spec#481

Signed-off-by: Siddhartha Singh <siddharthagithub0007@gmail.com>
@Siddhartha-singh01
Copy link
Copy Markdown
Contributor Author

Hi @mathieu-benoit

I have successfully updated and synchronized the branch with the latest changes from the main branch.

Could you please approve the workflows to run and review the updated changes whenever you get a chance?

Thank you!

@mathieu-benoit
Copy link
Copy Markdown
Contributor

Thanks @Siddhartha-singh01! For helping my review, could you please test and share the associated commands (before and after would be ideal):

  • score-compose init --provisioners FIXME-WITH-ASSOCIATED-PROVISIONER
  • score-compose provisioners list

Thanks!

@Siddhartha-singh01
Copy link
Copy Markdown
Contributor Author

Siddhartha-singh01 commented May 13, 2026

Hi @mathieu-benoit thanks for the feedback!

and sir if you feel anything to ask to validate the pr just ask

The environment provisioner is a builtin provisioner (registered programmatically in generate.go, not loaded from provisioner YAML files), so it doesn't appear in the output of score-compose provisioners list. However, I've tested the fix thoroughly here are the results:

Before (on main) Infinite Recursion Bug
The Provisioner struct methods called themselves recursively, causing a stack overflow crash whenever invoked:

func (p *Provisioner) Class() string { return p.Class() } // infinite recursion
func (p *Provisioner) Type() string { return p.Type() } // infinite recursion
func (p *Provisioner) Description() string { return p.Description() } // infinite recursion

After (this PR) Fixed
The methods now return the correct literal values, consistent with the existing Match() logic and the envVarResourceTracker sub-provisioner:
``
func (p *Provisioner) Class() string { return "default" } // consistent with Match()
func (p *Provisioner) Type() string { return "environment" } // consistent with Match()
func (p *Provisioner) Description() string { return "" } // consistent with envVarResourceTracker

Unit Test

image

CLI Test with enviroment resource

image image

Generated compose.yml output :

image

No crash, compose file generated successfully ✅

score-compose provisioners list :

image

The branch is also fully synced with the latest main .

Thanks!

@mathieu-benoit
Copy link
Copy Markdown
Contributor

Thanks for the details, what about the use of this one https://docs.score.dev/examples/resource-provisioners/community/environment/score-compose/cmd/dotenv/?

@Siddhartha-singh01
Copy link
Copy Markdown
Contributor Author

Thanks for the link, @mathieu-benoit

I see that the dotenv community provisioner is designed to load variables from a local .env file via a python script.

The builtin provisioner I've fixed specifically handles OS/shell environment variables via os.LookupEnv. By ensuring the builtin provisioner correctly returns its Type() and Class() without crashing, it allows the score-compose loader to safely manage both the builtin and community provisioners (like dotenv) during the resource matching phase.

My fix ensures that even if multiple environment provisioners are present, the builtin one won't cause a stack overflow when the framework tries to inspect it.

Copy link
Copy Markdown
Contributor

@mathieu-benoit mathieu-benoit left a comment

Choose a reason for hiding this comment

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

LGTM

@mathieu-benoit
Copy link
Copy Markdown
Contributor

@chris-stephenson, can we have your review on this one please? Thanks!

Copy link
Copy Markdown
Contributor

@chris-stephenson chris-stephenson left a comment

Choose a reason for hiding this comment

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

LGTM

@chris-stephenson
Copy link
Copy Markdown
Contributor

The Fix itself looks good - but I'm actually concerned about how the envprov is defined in general. It seems to be a bit of "magic" and would not be possible to override...

@Siddhartha-singh01
Copy link
Copy Markdown
Contributor Author

Thanks @chris-stephenson

That’s a fair point regarding the "magic" in the envprov definition. Currently, it’s quite tightly coupled to the environment resource resolution.

This fix ensures that the loader doesn't crash when multiple provisioners are present, but it doesn't yet solve the underlying "magic" of how they are prioritized or overridden. I'd love to help rethink that interface in a follow-up PR to make the provisioner registry more transparent.

@chris-stephenson
Copy link
Copy Markdown
Contributor

Yes, @Siddhartha-singh01 . While the environment resource type is "special" the provisioner should not be magic! The first step here is to create an issue for this. Is that something you want to create? Along the lines of allowing the developer to specify whether to use environment variable resolution or another provisioner of their choice (e.g. to read from a parameter store, .env file etc)

@Siddhartha-singh01
Copy link
Copy Markdown
Contributor Author

Absolutely, I'd be happy to create that issue!

I completely agree the current behavior where the built-in provisioner is implicitly wired to os.LookupEnv without any way for the developer to override it is too opaque. The environment resource type may be special in how it's handled internally, but the provisioner backing it should be an explicit, user-facing choice.

I'm envisioning the issue along these lines:

Problem: Today, when a Score file declares an environment resource, the resolution is hardcoded to OS environment variables. There's no configuration surface for a developer to say "use a .env file for local dev" or "use AWS SSM / HashiCorp Vault in production." This tight coupling makes the provisioner non-overridable and difficult to extend.

Proposed direction: Introduce an explicit provisioner selection mechanism so developers can configure their preferred source per resource whether that's OS env vars, a .env file, a parameter store, or a custom provider. The built-in os.LookupEnv behavior could remain as the default, but it should be one option among many rather than the only path.

I'll get the issue drafted and link it back here. Looking forward to collaborating on the design, @chris-stephenson !

@Siddhartha-singh01
Copy link
Copy Markdown
Contributor Author

@chris-stephenson Created the feature request in #488. Happy to pick that up once this fix is merged!

@mathieu-benoit mathieu-benoit merged commit f32abd8 into score-spec:main May 16, 2026
8 checks passed
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.

[bug] Infinite recursion in Provisioner.Class(), Type(), and Description() methods

3 participants