Skip to content

Fix local repo clone permissions and surface provisioning failures in the console#41

Merged
xlight05 merged 3 commits into
wso2:mainfrom
randilt:project-clone-error-fix
Jun 19, 2026
Merged

Fix local repo clone permissions and surface provisioning failures in the console#41
xlight05 merged 3 commits into
wso2:mainfrom
randilt:project-clone-error-fix

Conversation

@randilt

@randilt randilt commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Purpose

Fixes #40
On Linux local setups, project creation often failed silently: the BFF could not clone GitHub repos because the bind-mounted repo directory (~/specs/repos) was created root-owned by Docker while asdlc-api runs as uid 1000. The DB recorded git_repositories.status=error, but the console showed a misleading “No Git repository associated” empty state.

Resolves local repo clone permission failures and incorrect project overview UI for failed provisioning.

Goals

  • Ensure repo storage is writable by the API container before docker compose up
  • Stop mapping repo provisioning failures to the “no repo” phase
  • Show a clear, user-facing error in the console when repository setup fails

Approach

Deployments

  • Move the host bind mount from ${HOME}/specs/repos to deployments/data/repos
  • Add ensure_repo_storage() in deployments/scripts/utils.sh (mkdir -p + chmod 1777) and call it from start.sh before compose starts
  • Update teardown.sh to resolve the repo path from the asdlc-api service in docker-compose.yml

BFF

  • Add repo-error SDLC phase and repoErrorMessage on ProjectStatus
  • Extract applyRepoToProjectStatus() so error repo status is distinct from a missing repo

Console

  • Handle repo-error with a SaaS-friendly empty state (no deployment commands or raw backend errors)
  • Map known failure patterns to user-facing copy; link to GitHub settings when credentials/access are likely the cause

Git

  • Ignore deployments/data/repos/* (runtime clones); track only .gitkeep

User stories

  • As a developer on Linux, I can create a project and have its GitHub repo cloned without fixing filesystem permissions manually.
  • As a user, when repository setup fails, I see that setup failed and what to do next — not “create a new project”.

Release note

Fixed repository clone failures on Linux local deployments caused by bind-mount permissions, and improved the project overview when Git repository provisioning fails.

Documentation

N/A

Training

N/A

Certification

N/A — no certification exam impact.

Marketing

N/A

Automation tests

  • Unit tests
    • asdlc-service/services/project_status_test.goTestApplyRepoToProjectStatus covers no-repo, repo-cloning, repo-error, and ready continuation
  • Integration tests
    • N/A — deployment script behavior verified manually; no new API integration tests added

Security checks

Samples

N/A

Related PRs

N/A

Migrations (if applicable)

Local developers only:

  1. Pull this change
  2. Run cd deployments && bash scripts/start.sh
  3. Clones now live under deployments/data/repos/ (not ~/specs/repos)
  4. Projects stuck in error before the fix must be deleted and recreated

Optional: migrate existing clones with cp -a ~/specs/repos/. deployments/data/repos/

Tested on Linux (Docker Compose + k3d local setup).

Test environment

  • OS: Linux
  • Browser: Chrome/Firefox (console UI)
  • Backend: Go 1.26 (asdlc-api), Docker Compose local stack

Learning

Root cause was a classic Docker bind-mount ownership mismatch: missing host dirs created as root, container writes as uid 1000. Mac/Colima setups were more forgiving. Fix follows existing patterns in start.sh (kubeconfig + signing key permission prep) and uses a repo-local path like deployments/keys/.

@CLAassistant

CLAassistant commented Jun 12, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f3b343c1-74fc-4e27-b34d-6757ba355b20

📥 Commits

Reviewing files that changed from the base of the PR and between 03ed1e9 and daef20b.

📒 Files selected for processing (11)
  • .gitignore
  • asdlc-service/models/project.go
  • asdlc-service/services/project_service.go
  • asdlc-service/services/project_status_test.go
  • console/src/pages/ProjectOverviewPage.tsx
  • console/src/services/api/types.ts
  • deployments/data/repos/.gitkeep
  • deployments/docker-compose.yml
  • deployments/scripts/start.sh
  • deployments/scripts/teardown.sh
  • deployments/scripts/utils.sh
✅ Files skipped from review due to trivial changes (1)
  • .gitignore
🚧 Files skipped from review as they are similar to previous changes (8)
  • asdlc-service/services/project_status_test.go
  • deployments/scripts/utils.sh
  • deployments/docker-compose.yml
  • deployments/scripts/teardown.sh
  • deployments/scripts/start.sh
  • console/src/pages/ProjectOverviewPage.tsx
  • console/src/services/api/types.ts
  • asdlc-service/services/project_service.go

📝 Walkthrough

Overview

This PR fixes Linux local deployment failures where project repository cloning could fail due to host bind-mount permissions, and updates the console to surface repository provisioning failures with clearer, actionable messaging instead of a misleading “no repo” state.

Key Changes

Deployment Infrastructure

  • Repo storage location & mount: Updated the Docker Compose bind mount for repo storage to use ./data/repos (under deployments/data/repos on the host) instead of ${HOME}/specs/repos.
  • Permission/writability guarantees: Added ensure_repo_storage() to deployments/scripts/utils.sh to create the repo directory and set sticky, world-writable permissions (chmod 1777) so the asdlc-api container user can write before docker compose up.
  • Startup updates: Updated deployments/scripts/start.sh to run ensure_repo_storage() as part of the startup sequence (and adjusted related file permission handling).
  • Teardown robustness: Updated deployments/scripts/teardown.sh to resolve repo bind-mount paths from the asdlc-api service configuration (and normalize relative host paths) so cleanup of bind-mounted repo directories is accurate.
  • Script hardening: Made load_public_urls() tolerate missing .env keys so defaults apply even if some variables are absent.

Backend Status Handling (BFF)

  • New project phase: Introduced a "repo-error" phase in ProjectStatus (documented valid phase values).
  • Error propagation: Added optional repoErrorMessage (RepoErrorMessage) to ProjectStatus to carry repository provisioning error details when in the "repo-error" phase.
  • Correct phase mapping: Refactored repo-to-project lifecycle mapping by extracting applyRepoToProjectStatus() in project_service.go so:
    • repo status == "error" maps to "repo-error" (with repo.ErrorMessage)
    • repo pending/cloning maps to "repo-cloning"
    • missing repos no longer get incorrectly treated as repo failures

Console UX

  • Dedicated failure UI: Updated ProjectOverviewPage to handle phase === 'repo-error' via a RepoErrorState view.
  • Actionable guidance: Added describeRepoError logic to summarize known failure patterns and optionally offer an “Open GitHub settings” action when GitHub-related access/credential issues are likely.

Git Workspace Handling

  • .gitignore: Added rules to ignore runtime clones under deployments/data/repos/* while keeping deployments/data/repos/.gitkeep tracked.

Testing & Verification

  • Added TestApplyRepoToProjectStatus in asdlc-service/services/project_status_test.go covering nil, pending, cloning, error (including error message propagation), and ready cases.
  • Deployment script behavior verified manually on Linux with Docker Compose and k3d.

Migration Notes

Projects previously stuck in an error repo status must be deleted and recreated. An optional migration command is provided to transfer existing clones to the new repo location.

Walkthrough

This PR addresses repository cloning permission failures on Linux by establishing a complete error visibility and storage initialization system. The backend refactors project status computation to centralize repository state mapping, explicitly handling error states and propagating error messages into a new RepoErrorMessage field. The frontend introduces a RepoErrorState component that displays repository setup failures with pattern-matched error summaries and conditional GitHub settings navigation. Deployment infrastructure adds an ensure_repo_storage helper to prepare the bind-mount directory with correct permissions before services start, while docker-compose and teardown scripts are updated to support the new storage location with proper path normalization.

Sequence Diagram

sequenceDiagram
  participant API as asdlc-api Container
  participant Storage as Host Bind Mount
  participant DB as Project Status
  participant Console as Console UI

  API->>Storage: attempt to create repo directory
  Storage-->>API: permission denied (repo clone fails)
  API->>DB: set phase=repo-error, RepoErrorMessage=mkdir permission denied
  Console->>DB: fetch ProjectStatus
  DB-->>Console: phase=repo-error, repoErrorMessage
  Console->>Console: render RepoErrorState with error summary
  Console-->>API: show actionable error message
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the primary changes: fixing local repo clone permissions on Linux deployments and surfacing provisioning failures in the console UI.
Description check ✅ Passed The description comprehensively covers purpose, goals, approach, user stories, release notes, testing, and migrations. All major template sections are completed with sufficient detail.
Linked Issues check ✅ Passed All objectives from issue #40 are addressed: directory permissions are fixed with ensure_repo_storage(), repo-error phase surfaces provisioning failures, and the console displays actionable error messages instead of misleading 'no repo' state.
Out of Scope Changes check ✅ Passed All changes are directly scoped to issue #40: deployment scripts handle permissions, backend distinguishes repo errors from missing repos, console handles the new repo-error phase, and git ignores runtime data. No unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
asdlc-service/services/project_status_test.go (1)

66-81: ⚡ Quick win

Add an assertion for RepoURL mapping in the table tests.

The helper sets status.RepoURL, but this contract is not validated in the current assertions.

Proposed test addition
 			if c.repo != nil && status.RepoStatus != c.repo.Status {
 				t.Fatalf("repoStatus: got %q want %q", status.RepoStatus, c.repo.Status)
 			}
+			if c.repo != nil && status.RepoURL != c.repo.RepoURL {
+				t.Fatalf("repoUrl: got %q want %q", status.RepoURL, c.repo.RepoURL)
+			}
 			if status.RepoErrorMessage != c.wantErrMsg {
 				t.Fatalf("repoErrorMessage: got %q want %q", status.RepoErrorMessage, c.wantErrMsg)
 			}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@asdlc-service/services/project_status_test.go` around lines 66 - 81, The
table test is missing an assertion that applyRepoToProjectStatus sets
models.ProjectStatus.RepoURL; update the loop inside Test (where
applyRepoToProjectStatus is called) to assert that when c.repo != nil the
status.RepoURL equals c.repo.URL (and if your cases define an expected value use
c.wantRepoURL instead), e.g. add an if block similar to the RepoStatus check
that fails with t.Fatalf("repoURL: got %q want %q", status.RepoURL, c.repo.URL)
so the contract of applyRepoToProjectStatus -> ProjectStatus.RepoURL is
validated.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@asdlc-service/services/project_status_test.go`:
- Around line 66-81: The table test is missing an assertion that
applyRepoToProjectStatus sets models.ProjectStatus.RepoURL; update the loop
inside Test (where applyRepoToProjectStatus is called) to assert that when
c.repo != nil the status.RepoURL equals c.repo.URL (and if your cases define an
expected value use c.wantRepoURL instead), e.g. add an if block similar to the
RepoStatus check that fails with t.Fatalf("repoURL: got %q want %q",
status.RepoURL, c.repo.URL) so the contract of applyRepoToProjectStatus ->
ProjectStatus.RepoURL is validated.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d5a6d444-9a56-4908-93dc-c59e8887a374

📥 Commits

Reviewing files that changed from the base of the PR and between 0caa7a8 and 03ed1e9.

📒 Files selected for processing (11)
  • .gitignore
  • asdlc-service/models/project.go
  • asdlc-service/services/project_service.go
  • asdlc-service/services/project_status_test.go
  • console/src/pages/ProjectOverviewPage.tsx
  • console/src/services/api/types.ts
  • deployments/data/repos/.gitkeep
  • deployments/docker-compose.yml
  • deployments/scripts/start.sh
  • deployments/scripts/teardown.sh
  • deployments/scripts/utils.sh

randilt added 3 commits June 18, 2026 15:05
…file

Updated the load_public_urls function to handle cases where the specified environment file does not contain the expected variables. This change prevents the script from aborting due to grep returning a non-zero exit status when no matches are found, ensuring that default values are applied correctly.
Changed the permissions of the kubeconfig file to 644 to allow non-root containers to read it. Additionally, set the task signing key permissions to 644 to ensure proper access. This improves compatibility with non-root user setups in the deployment environment.
…sitory errors

- Updated ProjectStatus model to include RepoErrorMessage for better error reporting.
- Refactored GetProjectStatus to utilize a new helper function, applyRepoToProjectStatus, for cleaner logic and improved readability.
- Added RepoErrorState component in the ProjectOverviewPage to display user-friendly error messages when repository setup fails.
- Enhanced the describeRepoError function to provide specific guidance based on different error scenarios.
- Updated .gitignore to include new repository storage paths and ensure proper handling of project git clones.
- Introduced tests for applyRepoToProjectStatus to validate behavior across various repository states.
@randilt randilt force-pushed the project-clone-error-fix branch from 03ed1e9 to daef20b Compare June 18, 2026 09:35
@xlight05 xlight05 merged commit 5c66ac3 into wso2:main Jun 19, 2026
5 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.

Linux Local setup: repo clone fails with permission denied on ${HOME}/specs/repos bind mount

3 participants