Skip to content

Potential fix for code scanning alert no. 22: Uncontrolled data used in path expression - #28

Closed
intel352 wants to merge 1 commit into
mainfrom
alert-autofix-22
Closed

intel352 wants to merge 1 commit into
mainfrom
alert-autofix-22

Conversation

@intel352

Copy link
Copy Markdown
Contributor

Potential fix for https://github.com/GoCodeAlone/workflow/security/code-scanning/22

In general, the fix is to ensure that any user-controlled value used to build a path is validated or otherwise constrained so it cannot introduce path traversal or arbitrary filenames. For this particular case, the untrusted parameter is planID used in FileStateStore.GetPlan. The safest and least invasive fix is to validate planID before constructing the path, rejecting values that contain path separators, .., or that resolve outside the intended plans directory. This keeps existing functionality (plans are still stored and read from s.baseDir/plans/plan-<id>.json) while preventing malicious IDs from escaping that directory or manipulating the filename arbitrarily.

Concretely, in platform/providers/dockercompose/state_store.go inside GetPlan, we should:

  1. Define the plans directory once (dir := filepath.Join(s.baseDir, "plans")).
  2. Construct the filename from planID.
  3. Optionally normalize and/or validate planID:
    • If plan IDs are intended to be simple identifiers (which is likely), enforce that they consist only of a safe character set (for example, alphanumerics, dash, underscore) and reject others.
    • At minimum, reject any planID containing /, \, or ...
  4. Build the full path using that safe filename: filepath.Join(dir, "plan-"+planID+".json").
  5. Optionally use filepath.Abs to resolve the path and ensure it still lies within dir (defense in depth).

Because we are constrained to the shown snippets and existing imports, we will implement a simple explicit validation that rejects planID values containing path separators or ... This requires only the existing fmt and filepath imports; no new packages are needed. The change is localized to GetPlan and does not alter how plan IDs are generated or how files are named, aside from rejecting malicious IDs early.


Suggested fixes powered by Copilot Autofix. Review carefully before merging.

…in path expression

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
@intel352 intel352 closed this Feb 17, 2026
intel352 added a commit that referenced this pull request Apr 23, 2026
…re + follow-up TODOs

bootstrapStateBackend now dispatches by iac.state.backend:
- spaces → bootstrapStateBackendSpaces (DO endpoint URL constructed here)
- s3/gcs/azure → clear not-yet-implemented errors with contribution guidance
- filesystem/memory/postgres/"" → no-op

bootstrapStateBackendSpaces: exports WFCTL_STATE_BUCKET (generic) +
SPACES_BUCKET (backend-specific, no cloud-provider prefix). bootstrapDOSpacesBucket
now accepts caller-supplied endpoint; creds error message genericised; log
message updated to "created spaces state bucket".

resolveStateStore: wires module.PostgresIaCStateStore for backend=postgres;
s3/gcs/azure return clear errors instead of silent noop.

Misc:
- TODO(#28) added to deploy.go hardcoded credential checks
- TODO(#29) added to providerCredentialSubKeys map
- infra import --provider help text no longer lists specific providers
- All bootstrapDOSpacesBucketFn test fakes updated for new endpoint param
- CHANGELOG updated

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
intel352 added a commit that referenced this pull request Apr 23, 2026
…troy/status/drift direct paths + bootstrap URL export (#471)

* feat(wfctl): persist ResourceState after provider.Apply — fixes BMW state loss

Refactors applyWithProvider → applyWithProviderAndStore(ctx, provider,
providerType, specs, current, store). After provider.Apply returns success,
each ResourceOutput is written to the store; save failures log a loud warning
but do not abort the apply. Delete actions trigger store.DeleteResource after
the Apply call.

Also introduces resolveStateStore(cfgFile) which reads the iac.state module
config and instantiates the correct backend (filesystem or Spaces), rewriting
loadCurrentState to delegate to it so that remote backends are supported
beyond the previous filesystem-only path.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* feat(wfctl): direct-path infra destroy + status + drift for infra.* modules

Adds destroyInfraModules, statusInfraModules, and driftInfraModules that load
state from the configured backend, group records by IaCProvider, and dispatch
to provider.Destroy/Status/DetectDrift respectively.

runInfraDestroy, runInfraStatus, and runInfraDrift now dispatch to the direct
path when hasInfraModules() is true, falling back to the legacy pipeline path
for platform.* configs.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* feat(wfctl): bootstrap exports Spaces bucket URL back to config

After bootstrapStateBackend creates or confirms a DO Spaces bucket,
prints 'export DO_SPACES_BUCKET=<name>' to stdout for CI capture via
$GITHUB_ENV, and calls writeBucketBackToConfig to bake the resolved
bucket name into the on-disk YAML so downstream wfctl commands can read
state without the env var being set again.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* chore: add v0.18.6 CHANGELOG entry

* fix(lint): resolve 8 gocritic/nilerr issues in infra apply/destroy/status/drift

- Extract provider-loop bodies into closures (applyGroup, destroyGroup,
  statusGroup, driftGroup) to fix deferInLoop in all four files
- Switch range-value loops to index loops for rangeValCopy (plan.Actions
  136B, ResourceState 208B) in infra_apply, infra_destroy, infra_status_drift
- Split combined err+len guard in resolveStateStore to satisfy nilerr;
  add //nolint:nilerr on the intentional err-swallow (noop on missing config)

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* fix(wfctl): provider-agnostic bootstrap dispatch + postgres state store + follow-up TODOs

bootstrapStateBackend now dispatches by iac.state.backend:
- spaces → bootstrapStateBackendSpaces (DO endpoint URL constructed here)
- s3/gcs/azure → clear not-yet-implemented errors with contribution guidance
- filesystem/memory/postgres/"" → no-op

bootstrapStateBackendSpaces: exports WFCTL_STATE_BUCKET (generic) +
SPACES_BUCKET (backend-specific, no cloud-provider prefix). bootstrapDOSpacesBucket
now accepts caller-supplied endpoint; creds error message genericised; log
message updated to "created spaces state bucket".

resolveStateStore: wires module.PostgresIaCStateStore for backend=postgres;
s3/gcs/azure return clear errors instead of silent noop.

Misc:
- TODO(#28) added to deploy.go hardcoded credential checks
- TODO(#29) added to providerCredentialSubKeys map
- infra import --provider help text no longer lists specific providers
- All bootstrapDOSpacesBucketFn test fakes updated for new endpoint param
- CHANGELOG updated

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* refactor: BootstrapStateBackend → IaCProvider interface dispatch

Move all cloud-provider-specific bucket-creation logic out of wfctl core
and behind the IaCProvider plugin interface:

- interfaces/iac_provider.go: add BootstrapStateBackend(ctx, cfg)
  (*BootstrapResult, error) to IaCProvider; add BootstrapResult struct
  (Bucket, Region, Endpoint, EnvVars)
- infra_bootstrap.go: remove all DO/AWS SDK imports and S3-specific code;
  bootstrapStateBackend now finds the first iac.provider module, calls
  resolveIaCProvider, then delegates to provider.BootstrapStateBackend;
  self-contained backends (filesystem/memory/postgres/"") remain no-ops
- deploy_providers.go: wire BootstrapStateBackend on remoteIaCProvider
  via InvokeService + anyToStruct, consistent with rest of bridge
- All IaCProvider test stubs: add BootstrapStateBackend(nil, nil) stub
- Delete infra_bootstrap_bucket_test.go: DO-specific S3 tests move to
  DO plugin (follow-up #31, workflow-plugin-digitalocean v0.7.4)
- Rewrite infra_bootstrap_env_test.go + infra_bootstrap_url_export_test.go:
  replace bootstrapDOSpacesBucketFn overrides with resolveIaCProvider
  overrides using envBootstrapProvider / urlBootstrapProvider fakes
- Add infra_bootstrap_provider_test.go: TestBootstrapStateBackend_DispatchesToProvider
  (full round-trip), SelfContainedBackendsSkipped, NoProviderModuleErrors

Addresses review comment #3132352899 (intel352): DO-specific bootstrap
should not live in wfctl core.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.6 <[email protected]>
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.

1 participant