Skip to content

DSPX 2655 simplified workflow#438

Draft
dmihalcik-virtru wants to merge 17 commits intomainfrom
DSPX-2655-simplified-workflow
Draft

DSPX 2655 simplified workflow#438
dmihalcik-virtru wants to merge 17 commits intomainfrom
DSPX-2655-simplified-workflow

Conversation

@dmihalcik-virtru
Copy link
Copy Markdown
Member

  • feat(xtest): support platform-embedded otdfctl for migration to monorepo
  • fixup ruff format
  • fix(xtest): update remaining otdfctl references for platform monorepo migration
  • fixup pkg.go removes tag prefixes IIRC
  • refactor(xtest): consolidate .version and .module-path into single .version file
  • feat(sdk-mgr): wire --source option through install artifact command
  • fix(setup-cli-tool): avoid script injection by using env vars for inputs and step outputs
  • Apply suggestion from @gemini-code-assist[bot]
  • feat(setup-cli-tool): support multiple platform-source Go versions
  • fix: address PR review findings for platform otdfctl migration
  • fix(sdk-mgr): accept "standalone" as valid Go source in go_module_path
  • docs(xtest): clarify auto mode resolves releases from standalone
  • fix(setup-cli-tool): require SHA match in auto-detect platform fallback
  • fix: harden validation and error handling for platform otdfctl migration
  • fixup ruff format
  • refactor(xtest): extract composite actions from xtest.yml
  • Simplify xtest workflow with local runner

dmihalcik-virtru and others added 17 commits April 15, 2026 16:29
otdfctl is moving from opentdf/otdfctl into opentdf/platform. This
updates the test infrastructure to auto-detect when the platform
checkout contains otdfctl/ and build from there instead of the
standalone repo.

Key changes:
- xtest.yml: new otdfctl-source input (auto/standalone/platform) and
  detection step that checks for otdfctl/go.mod in the platform dir
- setup-cli-tool: new platform-otdfctl-dir input; symlinks platform
  source into sdk/go/src/ for head builds instead of separate checkout
- otdf-sdk-mgr: resolve.py supports go_source="platform" to resolve
  against the platform repo with otdfctl/ tag infix; installers write
  .module-path file for the new Go module path
- cli.sh/otdfctl.sh: read .module-path to use the correct module path
  (github.com/opentdf/platform/otdfctl) for go run fallback

Backward compatible: old releases still resolve from the standalone
repo; .module-path absence defaults to the original module path.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… migration

- artifactLink in xtest.yml now uses the correct pkg.go.dev module path
  based on the source field (platform vs standalone)
- registry.py list_go_versions() queries both the standalone otdfctl
  repo and the platform repo (otdfctl/ prefixed tags), deduplicating
  with platform entries taking precedence
- README.md documents both module paths for Go release installs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ersion file

The Go SDK version config now uses a single .version file with format
`module-path@version` (e.g., `github.com/opentdf/otdfctl@v0.24.0`)
instead of separate .version and .module-path files. Shell wrappers
fall back to the standalone module path for legacy bare-version files.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Allows specifying the source repo for Go CLI installs (e.g., --source platform)
to support the otdfctl migration from standalone repo to the platform monorepo.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…uts and step outputs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Replace global sdk_source/sdk_repo with per-version checkout decisions
so that multiple Go head versions from opentdf/platform at different
SHAs can be tested against each other (e.g. a platform PR vs main).

- Add platform-otdfctl-sha input for SHA-based matching of the existing
  platform checkout; versions with a different SHA get a fresh checkout
  of opentdf/platform into platform-src/{tag}/ with a symlink from
  otdfctl/ into src/{tag}/
- Wire OTDFCTL_SOURCE to the resolve-versions job when otdfctl-source
  is explicitly 'platform', so the resolver returns platform SHAs
- Preserve backward-compatible auto-detect behavior: when platform-
  otdfctl-dir is set but version-info lacks source:"platform", all
  head Go versions still symlink to the existing dir

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Pass --source flag through artifact install step so platform-sourced
  Go versions get the correct module path in .version files
- Strip tag infix (e.g., otdfctl/v0.24.0 → v0.24.0) before normalizing
  in install_go_release to avoid producing invalid version strings
- Move step output expansion to env: block in detect-otdfctl to prevent
  script injection (consistent with 0c1b428)
- Narrow except Exception to GitCommandError in registry.py platform
  tag query so programming bugs propagate instead of being swallowed
- Handle StopIteration explicitly in resolve.py with a clear
  "main branch not found" error message
- Validate source parameter in go_module_path() to reject typos
- Add symlink target existence checks after ln -sfn in action.yaml
- Add ::warning:: annotation when auto-detect fallback skips SHA
  verification
- Fix typo and minor comment/doc improvements

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The workflow input and CLI advertise "standalone" as a valid source, but
go_module_path rejected it with a ValueError. Add "standalone" to the
valid set so it maps to the default standalone module path, consistent
with go_git_url, go_tag_infix, and go_install_prefix.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The otdfctl-source description implied auto detects from the platform
checkout, but release resolution runs before that checkout exists. Update
the input description and inline comment to accurately reflect the
two-phase behavior: releases resolve from standalone, platform detection
applies only to head builds.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
In auto mode, setup-cli-tool previously symlinked all head Go versions
to the platform checkout without verifying the commit SHA. This meant
otdfctl-ref=my-feature could silently test the platform-embedded otdfctl
instead of opentdf/otdfctl@my-feature. Now the fallback only reuses the
platform checkout when the resolved SHA matches; otherwise it falls
through to a standalone checkout.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Validate PLATFORM_DIR before using it in detect-otdfctl to prevent
wrong-repo SHA when the directory is missing. Remove dead cross-repo SHA
comparison in auto-detect fallback (standalone and platform repos have
different commit histories). Add input validation to all go_* config
helpers and the OTDFCTL_SOURCE env var. Treat pre-warm failure as a hard
error for the platform module path. Use array pattern for source_args
to prevent shell word-splitting. Improve observability with ::warning::
annotations and version-override logging.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace ~300 lines of inline workflow steps with three reusable composite
actions and two new CLI commands, reducing xtest.yml from 770 to 524 lines.

New composite actions:
- setup-test-environment: consolidates otdfctl detection, platform version
  lookup, key management check, root key extraction, and multikas support
- setup-sdk-clients: wraps setup-cli-tool with SDK-appropriate caching,
  go.mod/java .env fixups, and make builds (one call per SDK)
- setup-kas-instances: starts all 6 KAS instances via otdf-local ci start-kas

New CLI commands:
- otdf-sdk-mgr go-fixup: bridges client go.mod to server shared modules
  for head builds (parallels existing java-fixup)
- otdf-local ci start-kas: starts KAS instances in CI and emits
  GITHUB_OUTPUT lines for log file paths

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 17, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9164d839-c29c-406c-9b53-db91cf4fd458

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch DSPX-2655-simplified-workflow

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sonarqubecloud
Copy link
Copy Markdown

@github-actions
Copy link
Copy Markdown

X-Test Failure Report

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces the xtest orchestration system to facilitate local replay of CI tests and improves SDK version management by supporting both standalone and platform-embedded Go otdfctl releases. The changes include new CI-specific commands, enhanced version resolution in otdf-sdk-mgr, and specialized GitHub Actions for test environment preparation. Technical feedback identifies several critical issues, including disconnected configuration fallback logic in the CI module, unsafe substring matching for branch resolution, and potential runtime errors in file operations and shell scripts caused by unsanitized tags or fragile JSON iteration in Bash.

Comment on lines +135 to +160
kas_template = platform_dir / "opentdf-kas-mode.yaml"
platform_config = platform_dir / "opentdf-dev.yaml"
if not kas_template.exists():
# Fall back to opentdf.yaml if opentdf-kas-mode.yaml doesn't exist
kas_template_alt = platform_dir / "opentdf.yaml"
if kas_template_alt.exists():
print_info(
f"Using {kas_template_alt} as KAS template (opentdf-kas-mode.yaml not found)"
)
else:
print_error(
f"Neither opentdf-kas-mode.yaml nor opentdf.yaml found in {platform_dir}"
)
raise typer.Exit(1)

if not platform_config.exists():
# Try opentdf.yaml as fallback
platform_config_alt = platform_dir / "opentdf.yaml"
if platform_config_alt.exists():
platform_config = platform_config_alt

# Build settings with CI-specific overrides
# We use a fresh xtest_root derived from this package's location
settings = Settings(
platform_dir=platform_dir,
)
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.

high

The fallback logic for kas_template and platform_config appears to be disconnected from the rest of the orchestration.

  1. The kas_template variable (lines 135-148) is checked for existence but never used again in the function. If the intention is to use this template for KAS instances, it should be passed to the Settings or the KASManager.
  2. The platform_config variable (lines 150-154) is updated with a fallback path, but it is not passed to the Settings constructor (lines 158-160). If the Settings class defaults to opentdf-dev.yaml, it will ignore the fallback found here, causing _prepare_kas_template to fail or modify the wrong file.

"tag": "main",
}
try:
sha, _ = next(tag for tag in all_heads if "refs/heads/main" in tag)
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.

high

The substring match "refs/heads/main" in tag is dangerous as it will match any branch containing that string (e.g., refs/heads/main-v2 or refs/heads/feature/main-fix). It should be an exact match to ensure the correct branch is resolved.

Suggested change
sha, _ = next(tag for tag in all_heads if "refs/heads/main" in tag)
sha, _ = next(tag for tag in all_heads if tag[1] == "refs/heads/main")

if sdk == "go" and version.source == "platform":
if version.sha == platform_sha and (platform_dir / "otdfctl").is_dir():
src_dir.parent.mkdir(parents=True, exist_ok=True)
src_dir.unlink(missing_ok=True)
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.

medium

Using unlink() on src_dir will raise an IsADirectoryError if the path exists as a real directory (e.g., from a previous run where git worktree add created a directory instead of a symlink). Since this path is intended to be replaced by a symlink or a worktree, it is safer to use a helper that handles both files/symlinks and directories.

Suggested change
src_dir.unlink(missing_ok=True)
shutil.rmtree(src_dir, ignore_errors=True)

workspace,
[
"--html",
str(results_dir / f"helper-{config.options.focus_sdk}-{platform_tag}.html"),
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.

medium

The platform_tag is used directly in the HTML report filename. If the tag contains slashes (e.g., otdfctl/v0.1.0 or a feature branch name), the pytest command will fail because it will attempt to write to a non-existent subdirectory. You should sanitize the tag before using it in a filename.

Suggested change
str(results_dir / f"helper-{config.options.focus_sdk}-{platform_tag}.html"),
str(results_dir / f"helper-{config.options.focus_sdk}-{_sanitize_name(platform_tag)}.html"),

&& contains(fromJSON(inputs.platform-heads), inputs.platform-tag)
shell: bash
run: |
for row in $(echo "$VERSION_INFO" | jq -c '.[]'); do
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.

medium

Iterating over JSON objects in a Bash for loop using jq -c is fragile because it relies on word splitting. If any field in the JSON (like a tag or error message) contains a space, the loop will break the object into multiple iterations. It is safer to use a while read loop.

        echo "$VERSION_INFO" | jq -c '.[]' | while read -r row; do

echo "version=$PLATFORM_TAG" >> "$GITHUB_OUTPUT"
exit
fi
PLATFORM_VERSION=$(go run ./service version 2>&1)
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.

medium

Capturing stderr into the PLATFORM_VERSION variable is risky. If go run emits any warnings (e.g., about the Go version or dependency deprecations), they will be appended to the version string, which will likely cause the subsequent awk semver check (line 126) to fail or produce incorrect results.

        PLATFORM_VERSION=$(go run ./service version)
        echo "version=$PLATFORM_VERSION" >> "$GITHUB_OUTPUT"

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