rpm-cli 0.1.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rpm_cli-0.1.3/.claude/settings.json +131 -0
- rpm_cli-0.1.3/.devcontainer/.devcontainer.postcreate.sh +459 -0
- rpm_cli-0.1.3/.devcontainer/VERSION +1 -0
- rpm_cli-0.1.3/.devcontainer/catalog-entry.json +13 -0
- rpm_cli-0.1.3/.devcontainer/devcontainer-functions.sh +304 -0
- rpm_cli-0.1.3/.devcontainer/devcontainer.json +213 -0
- rpm_cli-0.1.3/.devcontainer/fix-line-endings.py +117 -0
- rpm_cli-0.1.3/.devcontainer/nix-family-os/README.md +364 -0
- rpm_cli-0.1.3/.devcontainer/nix-family-os/tinyproxy-daemon.sh +435 -0
- rpm_cli-0.1.3/.devcontainer/nix-family-os/tinyproxy.conf.template +45 -0
- rpm_cli-0.1.3/.devcontainer/postcreate-wrapper.sh +55 -0
- rpm_cli-0.1.3/.devcontainer/project-setup.sh +29 -0
- rpm_cli-0.1.3/.devcontainer/wsl-family-os/README.md +331 -0
- rpm_cli-0.1.3/.devcontainer/wsl-family-os/tinyproxy-daemon.sh +440 -0
- rpm_cli-0.1.3/.devcontainer/wsl-family-os/tinyproxy.conf.template +45 -0
- rpm_cli-0.1.3/.github/CODEOWNERS +6 -0
- rpm_cli-0.1.3/.github/workflows/codeql-analysis.yml +31 -0
- rpm_cli-0.1.3/.github/workflows/main-validation.yml +350 -0
- rpm_cli-0.1.3/.github/workflows/pr-validation.yml +152 -0
- rpm_cli-0.1.3/.github/workflows/publish.yml +152 -0
- rpm_cli-0.1.3/.gitignore +20 -0
- rpm_cli-0.1.3/.pre-commit-config.yaml +29 -0
- rpm_cli-0.1.3/.tool-versions +2 -0
- rpm_cli-0.1.3/.yamllint +20 -0
- rpm_cli-0.1.3/CHANGELOG.md +107 -0
- rpm_cli-0.1.3/CLAUDE.md +1057 -0
- rpm_cli-0.1.3/CONTRIBUTING.md +203 -0
- rpm_cli-0.1.3/LICENSE +201 -0
- rpm_cli-0.1.3/Makefile +67 -0
- rpm_cli-0.1.3/PKG-INFO +739 -0
- rpm_cli-0.1.3/README.md +719 -0
- rpm_cli-0.1.3/docs/claude-marketplaces-guide.md +185 -0
- rpm_cli-0.1.3/docs/configuration.md +60 -0
- rpm_cli-0.1.3/docs/creating-manifest-repos.md +154 -0
- rpm_cli-0.1.3/docs/creating-packages.md +126 -0
- rpm_cli-0.1.3/docs/how-it-works.md +173 -0
- rpm_cli-0.1.3/docs/lifecycle.md +58 -0
- rpm_cli-0.1.3/docs/multi-source-guide.md +129 -0
- rpm_cli-0.1.3/docs/pipeline-integration.md +176 -0
- rpm_cli-0.1.3/docs/setup-guide.md +117 -0
- rpm_cli-0.1.3/docs/version-resolution.md +39 -0
- rpm_cli-0.1.3/git-hooks/pre-commit +14 -0
- rpm_cli-0.1.3/git-hooks/pre-push +34 -0
- rpm_cli-0.1.3/pyproject.toml +101 -0
- rpm_cli-0.1.3/requirements-dev.txt +9 -0
- rpm_cli-0.1.3/requirements.txt +1 -0
- rpm_cli-0.1.3/src/rpm_cli/__init__.py +3 -0
- rpm_cli-0.1.3/src/rpm_cli/__main__.py +5 -0
- rpm_cli-0.1.3/src/rpm_cli/catalog/gradle/build.gradle +42 -0
- rpm_cli-0.1.3/src/rpm_cli/catalog/gradle/rpm-bootstrap.gradle +70 -0
- rpm_cli-0.1.3/src/rpm_cli/catalog/make/Makefile +74 -0
- rpm_cli-0.1.3/src/rpm_cli/cli.py +67 -0
- rpm_cli-0.1.3/src/rpm_cli/commands/__init__.py +0 -0
- rpm_cli-0.1.3/src/rpm_cli/commands/bootstrap.py +70 -0
- rpm_cli-0.1.3/src/rpm_cli/commands/clean.py +40 -0
- rpm_cli-0.1.3/src/rpm_cli/commands/configure.py +109 -0
- rpm_cli-0.1.3/src/rpm_cli/commands/validate.py +133 -0
- rpm_cli-0.1.3/src/rpm_cli/core/__init__.py +0 -0
- rpm_cli-0.1.3/src/rpm_cli/core/bootstrap.py +159 -0
- rpm_cli-0.1.3/src/rpm_cli/core/catalog.py +134 -0
- rpm_cli-0.1.3/src/rpm_cli/core/clean.py +111 -0
- rpm_cli-0.1.3/src/rpm_cli/core/configure.py +347 -0
- rpm_cli-0.1.3/src/rpm_cli/core/marketplace.py +433 -0
- rpm_cli-0.1.3/src/rpm_cli/core/marketplace_validator.py +237 -0
- rpm_cli-0.1.3/src/rpm_cli/core/rpmenv.py +320 -0
- rpm_cli-0.1.3/src/rpm_cli/core/xml_validator.py +94 -0
- rpm_cli-0.1.3/src/rpm_cli/version.py +132 -0
- rpm_cli-0.1.3/tests/__init__.py +0 -0
- rpm_cli-0.1.3/tests/conftest.py +37 -0
- rpm_cli-0.1.3/tests/functional/__init__.py +0 -0
- rpm_cli-0.1.3/tests/functional/test_clean_lifecycle.py +94 -0
- rpm_cli-0.1.3/tests/functional/test_cli_entry_point.py +84 -0
- rpm_cli-0.1.3/tests/functional/test_configure_lifecycle.py +120 -0
- rpm_cli-0.1.3/tests/functional/test_validate_lifecycle.py +134 -0
- rpm_cli-0.1.3/tests/unit/__init__.py +0 -0
- rpm_cli-0.1.3/tests/unit/test_bootstrap.py +128 -0
- rpm_cli-0.1.3/tests/unit/test_catalog.py +160 -0
- rpm_cli-0.1.3/tests/unit/test_clean.py +111 -0
- rpm_cli-0.1.3/tests/unit/test_clean_command.py +22 -0
- rpm_cli-0.1.3/tests/unit/test_cli.py +67 -0
- rpm_cli-0.1.3/tests/unit/test_configure.py +195 -0
- rpm_cli-0.1.3/tests/unit/test_configure_command.py +42 -0
- rpm_cli-0.1.3/tests/unit/test_marketplace.py +357 -0
- rpm_cli-0.1.3/tests/unit/test_marketplace_validator.py +124 -0
- rpm_cli-0.1.3/tests/unit/test_rpmenv.py +189 -0
- rpm_cli-0.1.3/tests/unit/test_validate_command.py +48 -0
- rpm_cli-0.1.3/tests/unit/test_version.py +107 -0
- rpm_cli-0.1.3/tests/unit/test_xml_validator.py +64 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Read",
|
|
5
|
+
"Glob",
|
|
6
|
+
"Grep",
|
|
7
|
+
"WebFetch",
|
|
8
|
+
"Edit",
|
|
9
|
+
"Write",
|
|
10
|
+
"Bash(git status*)",
|
|
11
|
+
"Bash(git log*)",
|
|
12
|
+
"Bash(git show*)",
|
|
13
|
+
"Bash(git diff*)",
|
|
14
|
+
"Bash(git describe*)",
|
|
15
|
+
"Bash(git branch*)",
|
|
16
|
+
"Bash(git remote*)",
|
|
17
|
+
"Bash(git config --list*)",
|
|
18
|
+
"Bash(git tag --list*)",
|
|
19
|
+
"Bash(aws sso login*)",
|
|
20
|
+
"Bash(aws sts get-caller-identity*)",
|
|
21
|
+
"Bash(aws * describe-*)",
|
|
22
|
+
"Bash(aws * list-*)",
|
|
23
|
+
"Bash(aws * get-*)",
|
|
24
|
+
"Bash(aws s3 ls*)",
|
|
25
|
+
"Bash(argocd login*)",
|
|
26
|
+
"Bash(argocd * list*)",
|
|
27
|
+
"Bash(argocd * get*)",
|
|
28
|
+
"Bash(argocd * diff*)",
|
|
29
|
+
"Bash(argocd * logs*)",
|
|
30
|
+
"Bash(argocd * manifests*)",
|
|
31
|
+
"Bash(fly*login*)",
|
|
32
|
+
"Bash(fly pipelines*)",
|
|
33
|
+
"Bash(fly jobs*)",
|
|
34
|
+
"Bash(fly builds*)",
|
|
35
|
+
"Bash(fly workers*)",
|
|
36
|
+
"Bash(fly targets*)",
|
|
37
|
+
"Bash(fly status*)",
|
|
38
|
+
"Bash(gh auth login*)",
|
|
39
|
+
"Bash(gh auth status*)",
|
|
40
|
+
"Bash(gh * view*)",
|
|
41
|
+
"Bash(gh * list*)",
|
|
42
|
+
"Bash(gh * diff*)",
|
|
43
|
+
"Bash(jfrog config add*)",
|
|
44
|
+
"Bash(jfrog config show*)",
|
|
45
|
+
"Bash(jfrog rt search*)",
|
|
46
|
+
"Bash(jf config add*)",
|
|
47
|
+
"Bash(jf config show*)",
|
|
48
|
+
"Bash(jf rt search*)",
|
|
49
|
+
"Bash(snyk auth*)",
|
|
50
|
+
"Bash(snyk config*)",
|
|
51
|
+
"Bash(snyk test*)",
|
|
52
|
+
"Bash(snyk monitor*)",
|
|
53
|
+
"Bash(snyk --version*)",
|
|
54
|
+
"Bash(crane ls*)",
|
|
55
|
+
"Bash(crane manifest*)",
|
|
56
|
+
"Bash(crane config*)",
|
|
57
|
+
"Bash(crane digest*)",
|
|
58
|
+
"Bash(crane version*)",
|
|
59
|
+
"Bash(kubectl get*)",
|
|
60
|
+
"Bash(kubectl describe*)",
|
|
61
|
+
"Bash(kubectl logs*)",
|
|
62
|
+
"Bash(kubectl explain*)",
|
|
63
|
+
"Bash(kubectl api-resources*)",
|
|
64
|
+
"Bash(kubectl cluster-info*)",
|
|
65
|
+
"Bash(kubectl top*)",
|
|
66
|
+
"Bash(kubectl config view*)",
|
|
67
|
+
"Bash(helm list*)",
|
|
68
|
+
"Bash(helm status*)",
|
|
69
|
+
"Bash(helm get*)",
|
|
70
|
+
"Bash(helm history*)",
|
|
71
|
+
"Bash(helm show*)",
|
|
72
|
+
"Bash(helm search*)",
|
|
73
|
+
"Bash(helm repo list*)",
|
|
74
|
+
"Bash(ls*)",
|
|
75
|
+
"Bash(cat *)",
|
|
76
|
+
"Bash(head *)",
|
|
77
|
+
"Bash(tail *)",
|
|
78
|
+
"Bash(grep *)",
|
|
79
|
+
"Bash(find *)",
|
|
80
|
+
"Bash(tree*)",
|
|
81
|
+
"Bash(wc *)",
|
|
82
|
+
"Bash(diff *)",
|
|
83
|
+
"Bash(file *)",
|
|
84
|
+
"Bash(stat *)",
|
|
85
|
+
"Bash(pwd*)",
|
|
86
|
+
"Bash(which *)",
|
|
87
|
+
"Bash(env*)",
|
|
88
|
+
"Bash(printenv*)",
|
|
89
|
+
"Bash(xargs *)",
|
|
90
|
+
"Bash(code --list-extensions*)",
|
|
91
|
+
"Bash(asdf plugin list*)",
|
|
92
|
+
"Bash(asdf plugin add*)",
|
|
93
|
+
"Bash(asdf list all*)",
|
|
94
|
+
"Bash(asdf install*)",
|
|
95
|
+
"Bash(asdf reshim*)",
|
|
96
|
+
"Bash(asdf current*)",
|
|
97
|
+
"Bash(mkdir *)",
|
|
98
|
+
"Bash(cp *)",
|
|
99
|
+
"Bash(source ~/.bashrc*)",
|
|
100
|
+
"Bash(mv *)",
|
|
101
|
+
"Bash(rm *)",
|
|
102
|
+
"Bash(git add*)",
|
|
103
|
+
"Bash(git commit*)",
|
|
104
|
+
"Bash(git push*)"
|
|
105
|
+
],
|
|
106
|
+
"deny": [
|
|
107
|
+
"Bash(sed *)",
|
|
108
|
+
"Bash(awk *)",
|
|
109
|
+
"Bash(vi *)",
|
|
110
|
+
"Bash(vim *)",
|
|
111
|
+
"Bash(nano *)",
|
|
112
|
+
"Bash(emacs *)",
|
|
113
|
+
"Bash(tee *)",
|
|
114
|
+
"Bash(git merge*)",
|
|
115
|
+
"Bash(git rebase*)",
|
|
116
|
+
"Bash(docker build*)",
|
|
117
|
+
"Bash(docker run*)",
|
|
118
|
+
"Bash(docker push*)",
|
|
119
|
+
"Bash(kubectl apply*)",
|
|
120
|
+
"Bash(kubectl delete*)",
|
|
121
|
+
"Bash(kubectl edit*)",
|
|
122
|
+
"Bash(kubectl patch*)",
|
|
123
|
+
"Bash(helm install*)",
|
|
124
|
+
"Bash(helm upgrade*)",
|
|
125
|
+
"Bash(helm delete*)",
|
|
126
|
+
"Bash(aws s3 cp*)",
|
|
127
|
+
"Bash(aws s3 sync*)",
|
|
128
|
+
"Bash(aws s3 rm*)"
|
|
129
|
+
]
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
WORK_DIR=$(pwd)
|
|
6
|
+
CONTAINER_USER=$1
|
|
7
|
+
BASH_RC="/home/${CONTAINER_USER}/.bashrc"
|
|
8
|
+
ZSH_RC="/home/${CONTAINER_USER}/.zshrc"
|
|
9
|
+
WARNINGS=()
|
|
10
|
+
|
|
11
|
+
# Source shared functions
|
|
12
|
+
source "${WORK_DIR}/.devcontainer/devcontainer-functions.sh"
|
|
13
|
+
|
|
14
|
+
# Configure and log CICD environment
|
|
15
|
+
CICD_VALUE="${CICD:-false}"
|
|
16
|
+
if [ "$CICD_VALUE" = "true" ]; then
|
|
17
|
+
log_info "CICD environment variable: $CICD_VALUE"
|
|
18
|
+
log_info "Devcontainer configured to run in CICD mode (not a local dev environment)"
|
|
19
|
+
else
|
|
20
|
+
log_info "CICD environment variable: ${CICD:-not set}"
|
|
21
|
+
log_info "Devcontainer configured to run as a local developer environment"
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
log_info "Starting post-create setup..."
|
|
25
|
+
|
|
26
|
+
############################
|
|
27
|
+
# Create Python Symlink #
|
|
28
|
+
############################
|
|
29
|
+
if ! command -v python &> /dev/null; then
|
|
30
|
+
log_info "Creating python symlink to python3"
|
|
31
|
+
sudo ln -sf /usr/bin/python3 /usr/bin/python
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# Add Python tools to PATH for script execution
|
|
35
|
+
export PATH="/usr/local/py-utils/bin:/usr/local/python/current/bin:$HOME/.local/bin:$PATH"
|
|
36
|
+
|
|
37
|
+
#########################
|
|
38
|
+
# Require Critical Envs #
|
|
39
|
+
#########################
|
|
40
|
+
if [ -z "${DEFAULT_GIT_BRANCH:-}" ]; then
|
|
41
|
+
exit_with_error "❌ DEFAULT_GIT_BRANCH is not set in the environment"
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
if [ "$CICD_VALUE" != "true" ]; then
|
|
45
|
+
AWS_CONFIG_ENABLED="${AWS_CONFIG_ENABLED:-true}"
|
|
46
|
+
AWS_PROFILE_MAP_FILE="${WORK_DIR}/.devcontainer/aws-profile-map.json"
|
|
47
|
+
|
|
48
|
+
if [ "${AWS_CONFIG_ENABLED,,}" = "true" ]; then
|
|
49
|
+
if [ ! -f "$AWS_PROFILE_MAP_FILE" ]; then
|
|
50
|
+
exit_with_error "❌ Missing AWS profile config: $AWS_PROFILE_MAP_FILE (required when AWS_CONFIG_ENABLED=true)"
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
AWS_PROFILE_MAP_JSON=$(<"$AWS_PROFILE_MAP_FILE")
|
|
54
|
+
|
|
55
|
+
if ! jq empty <<< "$AWS_PROFILE_MAP_JSON" >/dev/null 2>&1; then
|
|
56
|
+
log_error "$AWS_PROFILE_MAP_JSON"
|
|
57
|
+
exit_with_error "❌ AWS_PROFILE_MAP_JSON is not valid JSON"
|
|
58
|
+
fi
|
|
59
|
+
else
|
|
60
|
+
log_info "AWS configuration disabled (AWS_CONFIG_ENABLED=${AWS_CONFIG_ENABLED})"
|
|
61
|
+
fi
|
|
62
|
+
else
|
|
63
|
+
log_info "CICD mode enabled - skipping AWS configuration validation"
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
#################
|
|
67
|
+
# Configure ENV #
|
|
68
|
+
#################
|
|
69
|
+
log_info "Configuring ENV vars..."
|
|
70
|
+
|
|
71
|
+
# Configure shell.env sourcing for all shells (interactive and non-interactive)
|
|
72
|
+
log_info "Configuring shell.env sourcing for all shells"
|
|
73
|
+
|
|
74
|
+
# Verify shell.env exists before configuring shells
|
|
75
|
+
if [ ! -f "${WORK_DIR}/shell.env" ]; then
|
|
76
|
+
exit_with_error "❌ shell.env not found at ${WORK_DIR}/shell.env"
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
# For bash: source in .bashrc (interactive) and via BASH_ENV (non-interactive)
|
|
80
|
+
echo "# Source project shell.env" >> "${BASH_RC}"
|
|
81
|
+
echo "source \"${WORK_DIR}/shell.env\"" >> "${BASH_RC}"
|
|
82
|
+
echo "export BASH_ENV=\"${WORK_DIR}/shell.env\"" >> "${BASH_RC}"
|
|
83
|
+
echo "export PATH=\"\$HOME/.local/bin:\$PATH\"" >> "${BASH_RC}"
|
|
84
|
+
echo "alias python=python3" >> "${BASH_RC}"
|
|
85
|
+
echo "alias pip=pip3" >> "${BASH_RC}"
|
|
86
|
+
|
|
87
|
+
# For zsh: source in .zshenv (covers all zsh shells - interactive and non-interactive)
|
|
88
|
+
echo "source \"${WORK_DIR}/shell.env\"" > /home/${CONTAINER_USER}/.zshenv
|
|
89
|
+
echo "export PATH=\"\$HOME/.local/bin:\$PATH\"" >> /home/${CONTAINER_USER}/.zshenv
|
|
90
|
+
echo "alias python=python3" >> /home/${CONTAINER_USER}/.zshenv
|
|
91
|
+
echo "alias pip=pip3" >> /home/${CONTAINER_USER}/.zshenv
|
|
92
|
+
|
|
93
|
+
##############################
|
|
94
|
+
# Install asdf & Tool Versions
|
|
95
|
+
##############################
|
|
96
|
+
log_info "Installing asdf..."
|
|
97
|
+
mkdir -p /home/${CONTAINER_USER}/.asdf
|
|
98
|
+
if ! git clone https://github.com/asdf-vm/asdf.git /home/${CONTAINER_USER}/.asdf --branch v0.15.0; then
|
|
99
|
+
exit_with_error "Failed to clone asdf repository — check network connectivity and proxy settings"
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
# Source asdf for the current script
|
|
103
|
+
export ASDF_DIR="/home/${CONTAINER_USER}/.asdf"
|
|
104
|
+
export ASDF_DATA_DIR="/home/${CONTAINER_USER}/.asdf"
|
|
105
|
+
. "/home/${CONTAINER_USER}/.asdf/asdf.sh"
|
|
106
|
+
|
|
107
|
+
# Make asdf available system-wide for AI agents
|
|
108
|
+
log_info "Configuring system-wide asdf access for AI agents..."
|
|
109
|
+
|
|
110
|
+
# Create plugins directory if it doesn't exist
|
|
111
|
+
mkdir -p /home/${CONTAINER_USER}/.asdf/plugins
|
|
112
|
+
|
|
113
|
+
# Create wrapper scripts for asdf tools in /usr/local/bin for direct access
|
|
114
|
+
log_info "Creating asdf wrapper scripts for direct access..."
|
|
115
|
+
|
|
116
|
+
# Create asdf wrapper script
|
|
117
|
+
if uname -r | grep -i microsoft > /dev/null; then
|
|
118
|
+
# WSL compatibility: Use sudo for /usr/local/bin access
|
|
119
|
+
sudo tee /usr/local/bin/asdf > /dev/null << ASDF_WRAPPER
|
|
120
|
+
#!/bin/bash
|
|
121
|
+
# Wrapper script for asdf that ensures proper environment
|
|
122
|
+
export ASDF_DIR="/home/${CONTAINER_USER}/.asdf"
|
|
123
|
+
export ASDF_DATA_DIR="/home/${CONTAINER_USER}/.asdf"
|
|
124
|
+
if [ -f "/home/${CONTAINER_USER}/.asdf/asdf.sh" ]; then
|
|
125
|
+
. "/home/${CONTAINER_USER}/.asdf/asdf.sh"
|
|
126
|
+
fi
|
|
127
|
+
exec /home/${CONTAINER_USER}/.asdf/bin/asdf "\$@"
|
|
128
|
+
ASDF_WRAPPER
|
|
129
|
+
sudo chmod +x /usr/local/bin/asdf
|
|
130
|
+
else
|
|
131
|
+
# Non-WSL: Direct write to /usr/local/bin
|
|
132
|
+
cat > /usr/local/bin/asdf << ASDF_WRAPPER
|
|
133
|
+
#!/bin/bash
|
|
134
|
+
# Wrapper script for asdf that ensures proper environment
|
|
135
|
+
export ASDF_DIR="/home/${CONTAINER_USER}/.asdf"
|
|
136
|
+
export ASDF_DATA_DIR="/home/${CONTAINER_USER}/.asdf"
|
|
137
|
+
if [ -f "/home/${CONTAINER_USER}/.asdf/asdf.sh" ]; then
|
|
138
|
+
. "/home/${CONTAINER_USER}/.asdf/asdf.sh"
|
|
139
|
+
fi
|
|
140
|
+
exec /home/${CONTAINER_USER}/.asdf/bin/asdf "\$@"
|
|
141
|
+
ASDF_WRAPPER
|
|
142
|
+
chmod +x /usr/local/bin/asdf
|
|
143
|
+
fi
|
|
144
|
+
|
|
145
|
+
# Create pip wrapper script that sources asdf environment
|
|
146
|
+
if uname -r | grep -i microsoft > /dev/null; then
|
|
147
|
+
# WSL compatibility: Use sudo for /usr/local/bin access
|
|
148
|
+
sudo tee /usr/local/bin/pip-asdf > /dev/null << PIP_WRAPPER
|
|
149
|
+
#!/bin/bash
|
|
150
|
+
# Wrapper script for pip that ensures asdf environment is loaded
|
|
151
|
+
export ASDF_DIR="/home/${CONTAINER_USER}/.asdf"
|
|
152
|
+
export ASDF_DATA_DIR="/home/${CONTAINER_USER}/.asdf"
|
|
153
|
+
if [ -f "/home/${CONTAINER_USER}/.asdf/asdf.sh" ]; then
|
|
154
|
+
. "/home/${CONTAINER_USER}/.asdf/asdf.sh"
|
|
155
|
+
fi
|
|
156
|
+
exec /home/${CONTAINER_USER}/.asdf/shims/pip "\$@"
|
|
157
|
+
PIP_WRAPPER
|
|
158
|
+
sudo chmod +x /usr/local/bin/pip-asdf
|
|
159
|
+
else
|
|
160
|
+
# Non-WSL: Direct write to /usr/local/bin
|
|
161
|
+
cat > /usr/local/bin/pip-asdf << PIP_WRAPPER
|
|
162
|
+
#!/bin/bash
|
|
163
|
+
# Wrapper script for pip that ensures asdf environment is loaded
|
|
164
|
+
export ASDF_DIR="/home/${CONTAINER_USER}/.asdf"
|
|
165
|
+
export ASDF_DATA_DIR="/home/${CONTAINER_USER}/.asdf"
|
|
166
|
+
if [ -f "/home/${CONTAINER_USER}/.asdf/asdf.sh" ]; then
|
|
167
|
+
. "/home/${CONTAINER_USER}/.asdf/asdf.sh"
|
|
168
|
+
fi
|
|
169
|
+
exec /home/${CONTAINER_USER}/.asdf/shims/pip "\$@"
|
|
170
|
+
PIP_WRAPPER
|
|
171
|
+
chmod +x /usr/local/bin/pip-asdf
|
|
172
|
+
fi
|
|
173
|
+
|
|
174
|
+
#################
|
|
175
|
+
# Oh My Zsh #
|
|
176
|
+
#################
|
|
177
|
+
if [ ! -d "/home/${CONTAINER_USER}/.oh-my-zsh" ]; then
|
|
178
|
+
log_info "Installing Oh My Zsh..."
|
|
179
|
+
OMZ_INSTALL_SCRIPT="/tmp/ohmyzsh-install-${RANDOM}.sh"
|
|
180
|
+
if ! curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh -o "${OMZ_INSTALL_SCRIPT}"; then
|
|
181
|
+
exit_with_error "Failed to download Oh My Zsh install script — check network connectivity and proxy settings"
|
|
182
|
+
fi
|
|
183
|
+
if [ ! -s "${OMZ_INSTALL_SCRIPT}" ]; then
|
|
184
|
+
exit_with_error "Oh My Zsh install script is empty or missing at ${OMZ_INSTALL_SCRIPT}"
|
|
185
|
+
fi
|
|
186
|
+
if ! sh "${OMZ_INSTALL_SCRIPT}" --unattended; then
|
|
187
|
+
rm -f "${OMZ_INSTALL_SCRIPT}"
|
|
188
|
+
exit_with_error "Oh My Zsh installation failed"
|
|
189
|
+
fi
|
|
190
|
+
rm -f "${OMZ_INSTALL_SCRIPT}"
|
|
191
|
+
else
|
|
192
|
+
log_info "Oh My Zsh already installed — skipping"
|
|
193
|
+
fi
|
|
194
|
+
|
|
195
|
+
cat <<'EOF' >> ${ZSH_RC}
|
|
196
|
+
export ZSH="$HOME/.oh-my-zsh"
|
|
197
|
+
ZSH_THEME="obraun"
|
|
198
|
+
ENABLE_CORRECTION="false"
|
|
199
|
+
HIST_STAMPS="%m/%d/%Y - %H:%M:%S"
|
|
200
|
+
source $ZSH/oh-my-zsh.sh
|
|
201
|
+
EOF
|
|
202
|
+
|
|
203
|
+
#################
|
|
204
|
+
# Configure AWS #
|
|
205
|
+
#################
|
|
206
|
+
if [ "$CICD_VALUE" != "true" ]; then
|
|
207
|
+
if [ "${AWS_CONFIG_ENABLED,,}" = "true" ]; then
|
|
208
|
+
log_info "Configuring AWS profiles..."
|
|
209
|
+
mkdir -p /home/${CONTAINER_USER}/.aws
|
|
210
|
+
mkdir -p /home/${CONTAINER_USER}/.aws/amazonq/cache
|
|
211
|
+
chown -R ${CONTAINER_USER}:${CONTAINER_USER} /home/${CONTAINER_USER}/.aws/amazonq
|
|
212
|
+
|
|
213
|
+
AWS_OUTPUT_FORMAT="${AWS_DEFAULT_OUTPUT:-json}"
|
|
214
|
+
jq -r 'to_entries[] |
|
|
215
|
+
"[profile \(.key)]\n" +
|
|
216
|
+
"sso_start_url = \(.value.sso_start_url)\n" +
|
|
217
|
+
"sso_region = \(.value.sso_region)\n" +
|
|
218
|
+
"sso_account_name = \(.value.account_name)\n" +
|
|
219
|
+
"sso_account_id = \(.value.account_id)\n" +
|
|
220
|
+
"sso_role_name = \(.value.role_name)\n" +
|
|
221
|
+
"region = \(.value.region)\n" +
|
|
222
|
+
"output = '"$AWS_OUTPUT_FORMAT"'\n" +
|
|
223
|
+
"sso_auto_populated = true\n"' <<< "$AWS_PROFILE_MAP_JSON" \
|
|
224
|
+
> /home/${CONTAINER_USER}/.aws/config
|
|
225
|
+
else
|
|
226
|
+
log_info "Skipping AWS profile configuration (AWS_CONFIG_ENABLED=${AWS_CONFIG_ENABLED})"
|
|
227
|
+
fi
|
|
228
|
+
else
|
|
229
|
+
log_info "CICD mode enabled - skipping AWS profile configuration"
|
|
230
|
+
fi
|
|
231
|
+
|
|
232
|
+
#####################
|
|
233
|
+
# Install Base Tools
|
|
234
|
+
#####################
|
|
235
|
+
log_info "Installing core packages..."
|
|
236
|
+
log_info "Proxy environment: HTTP_PROXY=${HTTP_PROXY:-unset} http_proxy=${http_proxy:-unset}"
|
|
237
|
+
if ! sudo apt-get update -qq; then
|
|
238
|
+
exit_with_error "apt-get update failed. Check proxy settings and network connectivity. HTTP_PROXY=${HTTP_PROXY:-unset}"
|
|
239
|
+
fi
|
|
240
|
+
if ! sudo apt-get install -y -qq curl vim-tiny git gh nmap sipcalc wget unzip zip netcat-openbsd bc; then
|
|
241
|
+
exit_with_error "apt-get install failed for core packages"
|
|
242
|
+
fi
|
|
243
|
+
|
|
244
|
+
##############################
|
|
245
|
+
# Install Optional Extra Tools
|
|
246
|
+
##############################
|
|
247
|
+
if [ -n "${EXTRA_APT_PACKAGES:-}" ]; then
|
|
248
|
+
log_info "Installing extra packages: ${EXTRA_APT_PACKAGES}"
|
|
249
|
+
if ! sudo apt-get install -y ${EXTRA_APT_PACKAGES}; then
|
|
250
|
+
exit_with_error "apt-get install failed for extra packages: ${EXTRA_APT_PACKAGES}"
|
|
251
|
+
fi
|
|
252
|
+
fi
|
|
253
|
+
|
|
254
|
+
if [ -f "${WORK_DIR}/.tool-versions" ] && grep -qE '^[a-zA-Z]' "${WORK_DIR}/.tool-versions"; then
|
|
255
|
+
log_info "Installing asdf plugins from .tool-versions..."
|
|
256
|
+
grep -E '^[a-zA-Z]' "${WORK_DIR}/.tool-versions" | cut -d' ' -f1 | while read -r plugin; do
|
|
257
|
+
install_asdf_plugin "$plugin"
|
|
258
|
+
done
|
|
259
|
+
|
|
260
|
+
log_info "Installing tools from .tool-versions..."
|
|
261
|
+
if ! asdf install; then
|
|
262
|
+
log_warn "❌ asdf install failed — tool versions may not be fully installed"
|
|
263
|
+
fi
|
|
264
|
+
|
|
265
|
+
log_info "Running asdf reshim..."
|
|
266
|
+
if ! asdf reshim; then
|
|
267
|
+
exit_with_error "❌ asdf reshim failed"
|
|
268
|
+
fi
|
|
269
|
+
else
|
|
270
|
+
log_info "No .tool-versions file found (or file is empty) — skipping asdf install"
|
|
271
|
+
fi
|
|
272
|
+
|
|
273
|
+
# Create symlinks in /usr/local/bin for direct access by AI agents
|
|
274
|
+
log_info "Creating symlinks for AI agent direct access..."
|
|
275
|
+
if [ -d "/home/${CONTAINER_USER}/.asdf/shims" ]; then
|
|
276
|
+
for shim in /home/${CONTAINER_USER}/.asdf/shims/*; do
|
|
277
|
+
if [ -f "$shim" ] && [ -x "$shim" ]; then
|
|
278
|
+
shim_name=$(basename "$shim")
|
|
279
|
+
if [ ! -e "/usr/local/bin/$shim_name" ]; then
|
|
280
|
+
if uname -r | grep -i microsoft > /dev/null; then
|
|
281
|
+
# WSL compatibility: Use sudo for /usr/local/bin access
|
|
282
|
+
sudo ln -s "$shim" "/usr/local/bin/$shim_name"
|
|
283
|
+
else
|
|
284
|
+
# Non-WSL: Direct symlink creation
|
|
285
|
+
ln -s "$shim" "/usr/local/bin/$shim_name"
|
|
286
|
+
fi
|
|
287
|
+
log_info "Created symlink: /usr/local/bin/$shim_name -> $shim"
|
|
288
|
+
fi
|
|
289
|
+
fi
|
|
290
|
+
done
|
|
291
|
+
fi
|
|
292
|
+
|
|
293
|
+
# Install Caylent Devcontainer CLI
|
|
294
|
+
log_info "Installing Caylent Devcontainer CLI..."
|
|
295
|
+
if [ -n "${CLI_VERSION:-}" ]; then
|
|
296
|
+
if [[ "${CLI_VERSION}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
297
|
+
log_info "Installing specific CLI version: ${CLI_VERSION}"
|
|
298
|
+
CLI_INSTALL_CMD="caylent-devcontainer-cli==${CLI_VERSION}"
|
|
299
|
+
else
|
|
300
|
+
exit_with_error "Invalid CLI_VERSION format: ${CLI_VERSION}. Expected format: X.Y.Z (e.g., 1.2.3)"
|
|
301
|
+
fi
|
|
302
|
+
else
|
|
303
|
+
log_info "Installing latest CLI version"
|
|
304
|
+
CLI_INSTALL_CMD="caylent-devcontainer-cli"
|
|
305
|
+
fi
|
|
306
|
+
|
|
307
|
+
install_with_pipx "${CLI_INSTALL_CMD}"
|
|
308
|
+
|
|
309
|
+
# Verify asdf is working properly (only if tools were configured)
|
|
310
|
+
if [ -f "${WORK_DIR}/.tool-versions" ] && grep -qE '^[a-zA-Z]' "${WORK_DIR}/.tool-versions"; then
|
|
311
|
+
log_info "Verifying asdf installation..."
|
|
312
|
+
if ! asdf current; then
|
|
313
|
+
exit_with_error "❌ asdf current failed - installation may be incomplete"
|
|
314
|
+
fi
|
|
315
|
+
else
|
|
316
|
+
log_info "No asdf tools configured — skipping verification"
|
|
317
|
+
fi
|
|
318
|
+
|
|
319
|
+
##############
|
|
320
|
+
# Host Proxy #
|
|
321
|
+
##############
|
|
322
|
+
# Proxy environment variables are sourced from shell.env (generated by write_shell_env).
|
|
323
|
+
# This section validates that host proxy is accessible when HOST_PROXY=true.
|
|
324
|
+
|
|
325
|
+
if [ "${HOST_PROXY:-false}" = "true" ]; then
|
|
326
|
+
if [ -z "${HOST_PROXY_URL:-}" ]; then
|
|
327
|
+
exit_with_error "❌ HOST_PROXY=true but HOST_PROXY_URL is not set. Set HOST_PROXY_URL in shell.env (e.g., http://host.docker.internal:3128)"
|
|
328
|
+
fi
|
|
329
|
+
|
|
330
|
+
parse_proxy_host_port "${HOST_PROXY_URL}"
|
|
331
|
+
|
|
332
|
+
if is_wsl; then
|
|
333
|
+
validate_host_proxy "${PROXY_PARSED_HOST}" "${PROXY_PARSED_PORT}" "${HOST_PROXY_TIMEOUT:-10}" "wsl-family-os/README.md"
|
|
334
|
+
else
|
|
335
|
+
validate_host_proxy "${PROXY_PARSED_HOST}" "${PROXY_PARSED_PORT}" "${HOST_PROXY_TIMEOUT:-10}" "nix-family-os/README.md"
|
|
336
|
+
fi
|
|
337
|
+
else
|
|
338
|
+
log_info "Host proxy not enabled (HOST_PROXY=${HOST_PROXY:-false}) - skipping validation"
|
|
339
|
+
fi
|
|
340
|
+
|
|
341
|
+
#############
|
|
342
|
+
# AWS Tools #
|
|
343
|
+
#############
|
|
344
|
+
log_info "Installing AWS SSO utilities..."
|
|
345
|
+
install_with_pipx "aws-sso-util"
|
|
346
|
+
|
|
347
|
+
###################
|
|
348
|
+
# Claude Code CLI #
|
|
349
|
+
###################
|
|
350
|
+
log_info "Installing Claude Code CLI..."
|
|
351
|
+
|
|
352
|
+
# Download install script first to ensure it succeeds before piping to bash
|
|
353
|
+
CLAUDE_INSTALL_SCRIPT="/tmp/claude-install-${RANDOM}.sh"
|
|
354
|
+
|
|
355
|
+
if ! sudo -u "${CONTAINER_USER}" curl -fsSL https://claude.ai/install.sh -o "${CLAUDE_INSTALL_SCRIPT}"; then
|
|
356
|
+
exit_with_error "❌ Failed to download Claude Code install script from https://claude.ai/install.sh - check network connectivity and proxy settings"
|
|
357
|
+
fi
|
|
358
|
+
|
|
359
|
+
# Verify script was downloaded and is not empty
|
|
360
|
+
if [ ! -s "${CLAUDE_INSTALL_SCRIPT}" ]; then
|
|
361
|
+
exit_with_error "❌ Claude Code install script is empty or missing at ${CLAUDE_INSTALL_SCRIPT}"
|
|
362
|
+
fi
|
|
363
|
+
|
|
364
|
+
# Execute install script
|
|
365
|
+
log_info "Executing Claude Code install script..."
|
|
366
|
+
if uname -r | grep -i microsoft > /dev/null; then
|
|
367
|
+
# WSL compatibility: Run directly without sudo -u
|
|
368
|
+
if ! PATH="/home/${CONTAINER_USER}/.local/bin:$PATH" bash "${CLAUDE_INSTALL_SCRIPT}"; then
|
|
369
|
+
rm -f "${CLAUDE_INSTALL_SCRIPT}"
|
|
370
|
+
exit_with_error "❌ Failed to execute Claude Code install script"
|
|
371
|
+
fi
|
|
372
|
+
else
|
|
373
|
+
# Non-WSL: Install as container user
|
|
374
|
+
if ! sudo -u "${CONTAINER_USER}" PATH="/home/${CONTAINER_USER}/.local/bin:$PATH" bash "${CLAUDE_INSTALL_SCRIPT}"; then
|
|
375
|
+
rm -f "${CLAUDE_INSTALL_SCRIPT}"
|
|
376
|
+
exit_with_error "❌ Failed to execute Claude Code install script"
|
|
377
|
+
fi
|
|
378
|
+
fi
|
|
379
|
+
|
|
380
|
+
# Clean up install script
|
|
381
|
+
rm -f "${CLAUDE_INSTALL_SCRIPT}"
|
|
382
|
+
|
|
383
|
+
log_info "Verifying Claude Code CLI installation..."
|
|
384
|
+
CLAUDE_BIN="/home/${CONTAINER_USER}/.local/bin/claude"
|
|
385
|
+
if [ ! -f "$CLAUDE_BIN" ]; then
|
|
386
|
+
exit_with_error "❌ Claude Code binary not found at expected location: $CLAUDE_BIN"
|
|
387
|
+
fi
|
|
388
|
+
|
|
389
|
+
if [ ! -x "$CLAUDE_BIN" ]; then
|
|
390
|
+
exit_with_error "❌ Claude Code binary exists but is not executable: $CLAUDE_BIN"
|
|
391
|
+
fi
|
|
392
|
+
|
|
393
|
+
CLAUDE_VERSION=$(sudo -u "${CONTAINER_USER}" "${CLAUDE_BIN}" --version 2>&1 || echo "unknown")
|
|
394
|
+
log_success "Claude Code CLI installed successfully: ${CLAUDE_VERSION}"
|
|
395
|
+
|
|
396
|
+
#################
|
|
397
|
+
# Configure Git #
|
|
398
|
+
#################
|
|
399
|
+
if [ "$CICD_VALUE" != "true" ]; then
|
|
400
|
+
log_info "Setting up Git credentials..."
|
|
401
|
+
|
|
402
|
+
if [ -z "${GIT_AUTH_METHOD:-}" ]; then
|
|
403
|
+
exit_with_error "❌ GIT_AUTH_METHOD is required. Please regenerate project files."
|
|
404
|
+
fi
|
|
405
|
+
|
|
406
|
+
# Shared git config (both methods)
|
|
407
|
+
configure_git_shared "${CONTAINER_USER}" "${GIT_USER}" "${GIT_USER_EMAIL}"
|
|
408
|
+
|
|
409
|
+
case "${GIT_AUTH_METHOD}" in
|
|
410
|
+
token)
|
|
411
|
+
configure_git_token "${CONTAINER_USER}" "${GIT_PROVIDER_URL}" "${GIT_USER}" "${GIT_TOKEN}"
|
|
412
|
+
;;
|
|
413
|
+
ssh)
|
|
414
|
+
configure_git_ssh "${CONTAINER_USER}" "${GIT_PROVIDER_URL}" "${WORK_DIR}"
|
|
415
|
+
;;
|
|
416
|
+
*)
|
|
417
|
+
exit_with_error "❌ Invalid GIT_AUTH_METHOD: '${GIT_AUTH_METHOD}'. Must be 'token' or 'ssh'."
|
|
418
|
+
;;
|
|
419
|
+
esac
|
|
420
|
+
else
|
|
421
|
+
log_info "CICD mode enabled - skipping Git configuration"
|
|
422
|
+
fi
|
|
423
|
+
|
|
424
|
+
###########
|
|
425
|
+
# Cleanup #
|
|
426
|
+
###########
|
|
427
|
+
log_info "Fixing ownership for ${CONTAINER_USER}"
|
|
428
|
+
chown -R ${CONTAINER_USER}:${CONTAINER_USER} /home/${CONTAINER_USER}
|
|
429
|
+
|
|
430
|
+
####################
|
|
431
|
+
# Warning Summary #
|
|
432
|
+
####################
|
|
433
|
+
if [ ${#WARNINGS[@]} -ne 0 ]; then
|
|
434
|
+
echo -e "\n⚠️ Completed with warnings:"
|
|
435
|
+
for warning in "${WARNINGS[@]}"; do
|
|
436
|
+
echo " - $warning"
|
|
437
|
+
done
|
|
438
|
+
else
|
|
439
|
+
log_success "Dev container setup completed with no warnings"
|
|
440
|
+
fi
|
|
441
|
+
|
|
442
|
+
#########################
|
|
443
|
+
# Project-Specific Setup #
|
|
444
|
+
#########################
|
|
445
|
+
log_info "Running project-specific setup script..."
|
|
446
|
+
if [ -f "${WORK_DIR}/.devcontainer/project-setup.sh" ]; then
|
|
447
|
+
if uname -r | grep -i microsoft > /dev/null; then
|
|
448
|
+
# WSL compatibility: Run directly without sudo -u
|
|
449
|
+
bash -c "source '${WORK_DIR}/shell.env' && source /home/${CONTAINER_USER}/.asdf/asdf.sh && cd '${WORK_DIR}' && BASH_ENV='${WORK_DIR}/.devcontainer/devcontainer-functions.sh' bash '${WORK_DIR}/.devcontainer/project-setup.sh'"
|
|
450
|
+
else
|
|
451
|
+
# Non-WSL: Use sudo -u to run as container user
|
|
452
|
+
sudo -u "${CONTAINER_USER}" bash -c "source '${WORK_DIR}/shell.env' && source /home/${CONTAINER_USER}/.asdf/asdf.sh && cd '${WORK_DIR}' && BASH_ENV='${WORK_DIR}/.devcontainer/devcontainer-functions.sh' bash '${WORK_DIR}/.devcontainer/project-setup.sh'"
|
|
453
|
+
fi
|
|
454
|
+
else
|
|
455
|
+
log_warn "No project-specific setup script found at ${WORK_DIR}/.devcontainer/project-setup.sh"
|
|
456
|
+
WARNINGS+=("No project-specific setup script found at ${WORK_DIR}/.devcontainer/project-setup.sh")
|
|
457
|
+
fi
|
|
458
|
+
|
|
459
|
+
exit 0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.0.0
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "default",
|
|
3
|
+
"description": "General-purpose Caylent development environment with Python, Node.js, AWS CLI, Docker, and Kubernetes tools.",
|
|
4
|
+
"tags": [
|
|
5
|
+
"general",
|
|
6
|
+
"multi-language",
|
|
7
|
+
"aws",
|
|
8
|
+
"kubernetes"
|
|
9
|
+
],
|
|
10
|
+
"maintainer": "Caylent Platform Team",
|
|
11
|
+
"min_cli_version": "2.0.0",
|
|
12
|
+
"catalog_url": "https://github.com/caylent-solutions/devcontainer.git@2.0.4"
|
|
13
|
+
}
|