devzone 0.0.0-stage → 0.5.1

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.
@@ -0,0 +1,72 @@
1
+ # Image de base de devzone : outils sans feature officielle, versions figées.
2
+ # Java, Node, Python, Docker, kubectl, helm et gh sont ajoutés par les features
3
+ # de devcontainer.json, par-dessus cette image.
4
+
5
+ # uv : binaire de l'image officielle (pas de script curl | sh)
6
+ ARG UV_VERSION=0.13.1
7
+ FROM ghcr.io/astral-sh/uv:${UV_VERSION} AS uv
8
+
9
+ FROM mcr.microsoft.com/devcontainers/base:ubuntu-24.04
10
+
11
+ # Versions : pour mettre à jour, changer la version ET l'empreinte sha256,
12
+ # puis Rebuild Container
13
+ ARG K9S_VERSION=0.51.0
14
+ ARG ACTIONLINT_VERSION=1.7.12
15
+ ARG GITLEAKS_VERSION=8.30.1
16
+ ARG KIND_VERSION=0.33.0
17
+ ARG RUFF_VERSION=0.17.0
18
+ ARG VULTURE_VERSION=2.16
19
+ # pytest : même version que la CI de repowarden (ci/requirements/e2e-python.in)
20
+ ARG PYTEST_VERSION=9.1.1
21
+
22
+ SHELL ["/bin/bash", "-o", "pipefail", "-c"]
23
+
24
+ # Contrôles shell de repowarden
25
+ RUN apt-get update \
26
+ && apt-get install -y --no-install-recommends shellcheck bats \
27
+ && rm -rf /var/lib/apt/lists/*
28
+
29
+ # k9s, actionlint (mêmes versions que la CI de repowarden), gitleaks, kind :
30
+ # installer <nom> <url> <sha256> : empreinte vérifiée avant d'installer quoi que ce soit dans /usr/local/bin
31
+ # (kind est un binaire seul, sans archive : installé à part, même vérification)
32
+ RUN set -eu; \
33
+ arch="$(dpkg --print-architecture)"; \
34
+ case "$arch" in \
35
+ arm64) gl_arch=arm64; \
36
+ k9s_sha=3ee05c82e5f9198928a4e86133608ba6a2c10a2244d6a7789e820f78319d640c; \
37
+ al_sha=325e971b6ba9bfa504672e29be93c24981eeb1c07576d730e9f7c8805afff0c6; \
38
+ gl_sha=e4a487ee7ccd7d3a7f7ec08657610aa3606637dab924210b3aee62570fb4b080; \
39
+ kind_sha=20022bee6cfcd5086cb7234d218e3454e6090022f2a8f55d1fa7fcf42c3867a2 ;; \
40
+ amd64) gl_arch=x64; \
41
+ k9s_sha=c3752ad51a5a4015a113819c4eeb6e55a4d0e4b8e652494797532f6fc8161dd7; \
42
+ al_sha=8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8; \
43
+ gl_sha=551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb; \
44
+ kind_sha=aee6151561422756b764a4ae28e7f44cda5af5a9eead3cc9985112b1de8d8e0d ;; \
45
+ *) echo "Architecture non prise en charge : $arch" >&2; exit 1 ;; \
46
+ esac; \
47
+ installer() { \
48
+ tmp="$(mktemp -d)"; \
49
+ curl -fsSL "$2" -o "$tmp/a.tar.gz"; \
50
+ echo "$3 $tmp/a.tar.gz" | sha256sum -c --quiet; \
51
+ tar -xzf "$tmp/a.tar.gz" -C "$tmp" "$1"; \
52
+ install -m 0755 "$tmp/$1" /usr/local/bin/"$1"; \
53
+ rm -rf "$tmp"; \
54
+ }; \
55
+ installer k9s "https://github.com/derailed/k9s/releases/download/v${K9S_VERSION}/k9s_Linux_${arch}.tar.gz" "$k9s_sha"; \
56
+ installer actionlint "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_${arch}.tar.gz" "$al_sha"; \
57
+ installer gitleaks "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_${gl_arch}.tar.gz" "$gl_sha"; \
58
+ curl -fsSL "https://github.com/kubernetes-sigs/kind/releases/download/v${KIND_VERSION}/kind-linux-${arch}" -o /tmp/kind; \
59
+ echo "$kind_sha /tmp/kind" | sha256sum -c --quiet; \
60
+ install -m 0755 /tmp/kind /usr/local/bin/kind; \
61
+ rm -f /tmp/kind
62
+
63
+ COPY --from=uv /uv /uvx /usr/local/bin/
64
+
65
+ # ruff, vulture (repowarden code-mort a besoin des deux) et pytest, installés pour
66
+ # tous les utilisateurs, avec un Python géré par uv hors du home
67
+ # (variables limitées au build : uv tool install reste dans ~/.local pour vscode)
68
+ RUN export UV_TOOL_DIR=/opt/uv/tools UV_TOOL_BIN_DIR=/usr/local/bin \
69
+ UV_PYTHON_INSTALL_DIR=/opt/uv/python \
70
+ && uv tool install "ruff==${RUFF_VERSION}" \
71
+ && uv tool install "vulture==${VULTURE_VERSION}" \
72
+ && uv tool install "pytest==${PYTEST_VERSION}"
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env bash
2
+ # À chaque démarrage, dans l'ordre : identité git (déduite du compte gh),
3
+ # clusters Kubernetes, puis récapitulatif de ce qui reste à faire (devzone).
4
+ # Séquentiel : le récapitulatif voit l'identité tout juste posée ; l'échec
5
+ # d'une étape n'empêche pas les suivantes.
6
+ ICI="$(dirname "$0")"
7
+ bash "$ICI/git-identite.sh" || echo "démarrage : identité git non traitée (bash $ICI/git-identite.sh)"
8
+ bash "$ICI/kube-config.sh" || echo "démarrage : clusters non traités (bash $ICI/kube-config.sh)"
9
+ echo
10
+ bash "$ICI/devzone"
@@ -0,0 +1,34 @@
1
+ {
2
+ "features": {
3
+ "ghcr.io/devcontainers/features/docker-in-docker:2": {
4
+ "version": "2.17.0",
5
+ "resolved": "ghcr.io/devcontainers/features/docker-in-docker@sha256:25b9f05705ffba7dbe503230ac76081419306f8c8bc88e0ce78c4ecd99a0c78c",
6
+ "integrity": "sha256:25b9f05705ffba7dbe503230ac76081419306f8c8bc88e0ce78c4ecd99a0c78c"
7
+ },
8
+ "ghcr.io/devcontainers/features/github-cli:1": {
9
+ "version": "1.1.3",
10
+ "resolved": "ghcr.io/devcontainers/features/github-cli@sha256:bd7ab48a832228f633239277552c30b353867fef2e5b037e064b4e64f0b843f2",
11
+ "integrity": "sha256:bd7ab48a832228f633239277552c30b353867fef2e5b037e064b4e64f0b843f2"
12
+ },
13
+ "ghcr.io/devcontainers/features/java:1": {
14
+ "version": "1.8.3",
15
+ "resolved": "ghcr.io/devcontainers/features/java@sha256:61a839211feda1e2a1f10646648a948e733e4d98d770f3a4b6698a3c5fc92abe",
16
+ "integrity": "sha256:61a839211feda1e2a1f10646648a948e733e4d98d770f3a4b6698a3c5fc92abe"
17
+ },
18
+ "ghcr.io/devcontainers/features/kubectl-helm-minikube:1": {
19
+ "version": "1.3.1",
20
+ "resolved": "ghcr.io/devcontainers/features/kubectl-helm-minikube@sha256:bbe8adf6b37fff8c67412ab0a4579f4c2f30bbaba1d9a5cebd9e38bade54025b",
21
+ "integrity": "sha256:bbe8adf6b37fff8c67412ab0a4579f4c2f30bbaba1d9a5cebd9e38bade54025b"
22
+ },
23
+ "ghcr.io/devcontainers/features/node:1": {
24
+ "version": "1.7.1",
25
+ "resolved": "ghcr.io/devcontainers/features/node@sha256:8c0de46939b61958041700ee89e3493f3b2e4131a06dc46b4d9423427d06e5f6",
26
+ "integrity": "sha256:8c0de46939b61958041700ee89e3493f3b2e4131a06dc46b4d9423427d06e5f6"
27
+ },
28
+ "ghcr.io/devcontainers/features/python:1": {
29
+ "version": "1.8.0",
30
+ "resolved": "ghcr.io/devcontainers/features/python@sha256:fbcad6955caeecc5ad3f7886baf652e25cba5225a6c4c2287c536de2e5607511",
31
+ "integrity": "sha256:fbcad6955caeecc5ad3f7886baf652e25cba5225a6c4c2287c536de2e5607511"
32
+ }
33
+ }
34
+ }
@@ -0,0 +1,91 @@
1
+ {
2
+ "name": "devzone",
3
+ // Image de base + outils figés (k9s, uv, actionlint, gitleaks…) : voir Dockerfile
4
+ "build": { "dockerfile": "Dockerfile" },
5
+
6
+ "features": {
7
+ "ghcr.io/devcontainers/features/java:1": {
8
+ "version": "21",
9
+ "jdkDistro": "tem",
10
+ "installMaven": true
11
+ },
12
+ "ghcr.io/devcontainers/features/node:1": {
13
+ "version": "lts",
14
+ "pnpmVersion": "latest"
15
+ },
16
+ "ghcr.io/devcontainers/features/python:1": {
17
+ "version": "3.12",
18
+ // Pas d'outils pipx : leur lanceur « python -E » ignore PYTHONPATH et
19
+ // PYTHONPYCACHEPREFIX, dont repowarden a besoin pour lancer les tests
20
+ // (ruff, vulture et pytest viennent du Dockerfile, par uv)
21
+ "installTools": false
22
+ },
23
+ "ghcr.io/devcontainers/features/docker-in-docker:2": {},
24
+ "ghcr.io/devcontainers/features/kubectl-helm-minikube:1": {
25
+ "minikube": "none"
26
+ },
27
+ // gh : tickets, PR, protection (repowarden)
28
+ "ghcr.io/devcontainers/features/github-cli:1": {}
29
+ },
30
+
31
+ // Toujours /workspaces/devzone, quel que soit le nom du dossier sur l'hôte
32
+ // (npx devzone <dossier>) : scripts et chemins du conteneur en dépendent
33
+ "workspaceMount": "source=${localWorkspaceFolder},target=/workspaces/devzone,type=bind,consistency=cached",
34
+ "workspaceFolder": "/workspaces/devzone",
35
+
36
+ // Caches persistants : survivent aux rebuilds du conteneur. Préfixe des
37
+ // volumes : devzone, ou DEVZONE_VOLUMES (tests fonctionnels, isolés)
38
+ "mounts": [
39
+ "source=${localEnv:DEVZONE_VOLUMES:devzone}-m2,target=/home/vscode/.m2,type=volume",
40
+ "source=${localEnv:DEVZONE_VOLUMES:devzone}-pnpm,target=/home/vscode/.local/share/pnpm,type=volume",
41
+ // Assistants IA : connexion et réglages gardés d'un rebuild à l'autre
42
+ "source=${localEnv:DEVZONE_VOLUMES:devzone}-claude,target=/home/vscode/.claude,type=volume",
43
+ "source=${localEnv:DEVZONE_VOLUMES:devzone}-opencode-config,target=/home/vscode/.config/opencode,type=volume",
44
+ "source=${localEnv:DEVZONE_VOLUMES:devzone}-opencode-data,target=/home/vscode/.local/share/opencode,type=volume",
45
+ // Connexion gh et identité git (~/.config/git/config, lu par git comme
46
+ // config globale) : le conteneur reconstruit peut commiter et pousser
47
+ "source=${localEnv:DEVZONE_VOLUMES:devzone}-gh,target=/home/vscode/.config/gh,type=volume",
48
+ "source=${localEnv:DEVZONE_VOLUMES:devzone}-git,target=/home/vscode/.config/git,type=volume",
49
+ // Modules activés (devzone activer|desactiver), propres à chaque utilisateur
50
+ "source=${localEnv:DEVZONE_VOLUMES:devzone}-config,target=/home/vscode/.config/devzone,type=volume"
51
+ ],
52
+
53
+ "runArgs": [
54
+ // Cluster Kubernetes de l'hôte : sa config en lecture seule, adaptée au
55
+ // conteneur par kube-config.sh. HOME (Mac, Linux) ou USERPROFILE (Windows) ;
56
+ // -v plutôt que mounts : crée ~/.kube s'il manque au lieu d'échouer
57
+ "-v", "${localEnv:HOME}${localEnv:USERPROFILE}/.kube:/home/vscode/.kube-host:ro",
58
+ // host.docker.internal existe d'office avec Docker Desktop, pas sous Linux
59
+ "--add-host=host.docker.internal:host-gateway"
60
+ ],
61
+
62
+ "postCreateCommand": "bash .devcontainer/post-create.sh",
63
+ // Identité git, clusters, puis récapitulatif de ce qui reste à faire
64
+ "postStartCommand": "bash .devcontainer/demarrage.sh",
65
+ // Clusters kind du conteneur (config) + cluster de l'hôte (hote.config,
66
+ // refait à chaque démarrage par kube-config.sh)
67
+ "remoteEnv": {
68
+ "KUBECONFIG": "/home/vscode/.kube/config:/home/vscode/.kube/hote.config",
69
+ // Claude Code range aussi .claude.json (connexion, réglages) dans ce
70
+ // dossier, donc dans son volume, au lieu de ~/.claude.json
71
+ "CLAUDE_CONFIG_DIR": "/home/vscode/.claude"
72
+ },
73
+ "remoteUser": "vscode",
74
+
75
+ "customizations": {
76
+ "vscode": {
77
+ "extensions": [
78
+ "vscjava.vscode-java-pack",
79
+ "vmware.vscode-boot-dev-pack",
80
+ "dbaeumer.vscode-eslint",
81
+ "esbenp.prettier-vscode",
82
+ "bradlc.vscode-tailwindcss",
83
+ "ms-python.python",
84
+ "charliermarsh.ruff",
85
+ "ms-azuretools.vscode-docker",
86
+ "ms-kubernetes-tools.vscode-kubernetes-tools",
87
+ "redhat.vscode-yaml"
88
+ ]
89
+ }
90
+ }
91
+ }
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env bash
2
+ # Modules facultatifs de devzone, activés à la demande, sans rebuild :
3
+ # devzone état des modules
4
+ # devzone activer <module> active et applique tout de suite
5
+ # devzone desactiver <module> désactive et applique tout de suite
6
+ # devzone appliquer installe ce qui est actif (post-create.sh)
7
+ # devzone actif <module> code 0 si actif (scripts de démarrage)
8
+ # État propre à chaque utilisateur : ~/.config/devzone/modules (volume
9
+ # devzone-config, survit aux rebuilds), une ligne « module=on|off ».
10
+ set -euo pipefail
11
+
12
+ ETAT="${DEVZONE_ETAT:-$HOME/.config/devzone/modules}"
13
+ ICI="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)"
14
+ MODULES=(ia kubernetes)
15
+
16
+ # Assistants IA, versions figées : mettre à jour ici, puis devzone appliquer
17
+ # (ou Rebuild Container)
18
+ IA_PAQUETS=(@anthropic-ai/claude-code@2.1.286 opencode-ai@1.18.34)
19
+ IA_NOMS=(@anthropic-ai/claude-code opencode-ai)
20
+
21
+ description() {
22
+ case "$1" in
23
+ ia) echo "assistants IA : Claude Code, opencode" ;;
24
+ kubernetes) echo "connexion au cluster de l'hôte et metrics-server au démarrage" ;;
25
+ esac
26
+ }
27
+
28
+ connu() {
29
+ local m
30
+ for m in "${MODULES[@]}"; do [ "$m" = "$1" ] && return 0; done
31
+ return 1
32
+ }
33
+
34
+ # Premier démarrage (aucun état) : tout désactivé, sauf ia si une connexion
35
+ # existe déjà dans les volumes (pas de régression pour qui s'en servait)
36
+ initialiser() {
37
+ [ -f "$ETAT" ] && return 0
38
+ mkdir -p "$(dirname "$ETAT")"
39
+ local ia=off
40
+ if [ -f "$HOME/.claude/.credentials.json" ] || [ -f "$HOME/.local/share/opencode/auth.json" ]; then
41
+ ia=on
42
+ # stderr : initialiser est aussi appelé dans $(valeur …)
43
+ echo "devzone : connexion d'un assistant IA trouvée, module ia activé (devzone desactiver ia pour le retirer)" >&2
44
+ fi
45
+ printf 'ia=%s\nkubernetes=off\n' "$ia" >"$ETAT"
46
+ }
47
+
48
+ valeur() {
49
+ initialiser
50
+ local v
51
+ v="$(grep -E "^$1=" "$ETAT" | tail -1 | cut -d= -f2 || true)"
52
+ [ "$v" = on ] && echo on || echo off
53
+ }
54
+
55
+ ecrire() {
56
+ initialiser
57
+ local tmp
58
+ tmp="$(mktemp)"
59
+ grep -vE "^$1=" "$ETAT" >"$tmp" || true
60
+ echo "$1=$2" >>"$tmp"
61
+ mv "$tmp" "$ETAT"
62
+ }
63
+
64
+ appliquer_ia() {
65
+ if [ "$1" = on ]; then
66
+ npm install -g --no-fund --no-audit --loglevel=error "${IA_PAQUETS[@]}" >/dev/null
67
+ echo "devzone : ia actif : claude (puis /login), opencode auth login"
68
+ else
69
+ npm uninstall -g "${IA_NOMS[@]}" >/dev/null 2>&1 || true
70
+ echo "devzone : ia désactivé (connexions gardées dans leurs volumes)"
71
+ fi
72
+ }
73
+
74
+ appliquer_kubernetes() {
75
+ if [ "$1" = on ]; then
76
+ bash "$ICI/kube-config.sh"
77
+ else
78
+ rm -f "$HOME/.kube/hote.config"
79
+ echo "devzone : kubernetes désactivé (metrics-server reste installé sur les clusters où il l'a été)"
80
+ fi
81
+ }
82
+
83
+ # État complet : ✔ prêt, ✖ nécessaire, ○ facultatif, ⚠ à corriger ; chaque
84
+ # point à faire avec sa commande (affiché à chaque démarrage)
85
+ etat() {
86
+ local nom email statut m
87
+ echo "devzone : état (devzone pour le réafficher)"
88
+ nom="$(git config --get user.name || true)"
89
+ email="$(git config --get user.email || true)"
90
+ if [ -n "$nom" ] && [ -n "$email" ]; then
91
+ echo " ✔ identité git $nom <$email>"
92
+ else
93
+ echo " ✖ identité git nécessaire pour commiter : gh auth login -s workflow (automatique),"
94
+ echo " ou git config --file ~/.config/git/config user.name \"<nom>\" et user.email \"<email>\""
95
+ fi
96
+ if ! statut="$(gh auth status 2>&1)"; then
97
+ echo " ○ GitHub facultatif (push et PR, tickets repowarden) : gh auth login -s workflow"
98
+ elif grep -q "Token scopes:" <<<"$statut" && ! grep -q "'workflow'" <<<"$statut"; then
99
+ echo " ⚠ GitHub connecté, sans permission workflow (push de .github/workflows/ refusé) : gh auth refresh -h github.com -s workflow"
100
+ else
101
+ echo " ✔ GitHub connecté"
102
+ fi
103
+ for m in "${MODULES[@]}"; do
104
+ if [ "$(valeur "$m")" = on ]; then
105
+ printf ' ✔ module %-10s actif : %s\n' "$m" "$(description "$m")"
106
+ else
107
+ printf ' ○ module %-10s facultatif, %s : devzone activer %s\n' "$m" "$(description "$m")" "$m"
108
+ fi
109
+ done
110
+ }
111
+
112
+ changer() {
113
+ local m="${2:-}"
114
+ if [ -z "$m" ] || ! connu "$m"; then
115
+ echo "devzone : module inconnu : ${m:-(aucun)} ; modules : ${MODULES[*]}" >&2
116
+ exit 1
117
+ fi
118
+ ecrire "$m" "$1"
119
+ "appliquer_$m" "$1"
120
+ }
121
+
122
+ case "${1:-}" in
123
+ "" | etat | modules) etat ;;
124
+ activer) changer on "${2:-}" ;;
125
+ desactiver) changer off "${2:-}" ;;
126
+ appliquer)
127
+ [ "$(valeur ia)" = off ] || appliquer_ia on
128
+ ;;
129
+ actif)
130
+ connu "${2:-}" || { echo "devzone : module inconnu : ${2:-(aucun)}" >&2; exit 2; }
131
+ [ "$(valeur "$2")" = on ]
132
+ ;;
133
+ -h | --help | aide) sed -n '2,8p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//' ;;
134
+ *)
135
+ echo "devzone : commande inconnue : $1 (devzone --help)" >&2
136
+ exit 1
137
+ ;;
138
+ esac
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env bash
2
+ # Identité git, à chaque démarrage tant qu'elle manque : déduite du compte gh
3
+ # (propre à chaque utilisateur, connexion gardée dans son volume) et écrite dans
4
+ # ~/.config/git/config (volume devzone-git, survit aux rebuilds).
5
+ # Une identité déjà définie (à la main, ou recopiée par VS Code dans
6
+ # ~/.gitconfig) n'est jamais remplacée. Email noreply de GitHub : les commits
7
+ # sont rattachés au compte sans exposer l'email personnel.
8
+ set -euo pipefail
9
+
10
+ CONFIG="$HOME/.config/git/config"
11
+ nom_git="$(git config --get user.name || true)"
12
+ email_git="$(git config --get user.email || true)"
13
+
14
+ [ -n "$nom_git" ] && [ -n "$email_git" ] && exit 0
15
+
16
+ # Sans gh : rien à déduire ; le récapitulatif de devzone le signale
17
+ gh auth status >/dev/null 2>&1 || exit 0
18
+
19
+ id="" login="" nom=""
20
+ IFS=$'\t' read -r id login nom < <(gh api user --jq '[.id, .login, (.name // "")] | @tsv' 2>/dev/null || true)
21
+ if [ -z "$id" ] || [ -z "$login" ]; then
22
+ echo "git-identite : compte GitHub illisible (réseau ?) ; relancer : bash .devcontainer/git-identite.sh"
23
+ exit 0
24
+ fi
25
+
26
+ [ -n "$nom_git" ] || git config --file "$CONFIG" user.name "${nom:-$login}"
27
+ [ -n "$email_git" ] || git config --file "$CONFIG" user.email "${id}+${login}@users.noreply.github.com"
28
+ echo "git-identite : $(git config --get user.name) <$(git config --get user.email)>"
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env bash
2
+ # Clusters Kubernetes du conteneur, à chaque démarrage (le port du cluster de
3
+ # l'hôte peut changer) :
4
+ # - ~/.kube/hote.config : copie du ~/.kube de l'hôte (monté en lecture seule) où
5
+ # 127.0.0.1/localhost deviennent host.docker.internal, l'hôte vu du conteneur ;
6
+ # tls-server-name garde le nom attendu par le certificat
7
+ # - ~/.kube/config : clusters kind du conteneur, jamais touché ici
8
+ # KUBECONFIG (devcontainer.json) combine les deux.
9
+ # Module kubernetes (devzone activer kubernetes) : connexion au cluster de
10
+ # l'hôte et metrics-server seulement s'il est actif ; les contextes kind sont
11
+ # toujours remis (un cluster créé à la main reste utilisable).
12
+ set -euo pipefail
13
+
14
+ ICI="$(dirname "$0")"
15
+ module=off
16
+ bash "$ICI/devzone" actif kubernetes && module=on
17
+
18
+ # DEVZONE_KUBE_SOURCE : tests fonctionnels (jamais le cluster de l'hôte)
19
+ SOURCE="${DEVZONE_KUBE_SOURCE:-$HOME/.kube-host/config}"
20
+ HOTE="$HOME/.kube/hote.config"
21
+
22
+ mkdir -p "$HOME/.kube"
23
+ rm -f "$HOTE"
24
+ # Doit exister : sinon kind écrit dans hote.config, effacé au prochain démarrage
25
+ [ -f "$HOME/.kube/config" ] || install -m 600 /dev/null "$HOME/.kube/config"
26
+
27
+ if [ "$module" = on ] && [ -f "$SOURCE" ]; then
28
+ install -m 600 "$SOURCE" "$HOTE"
29
+ KUBECONFIG="$HOTE" kubectl config view \
30
+ -o jsonpath='{range .clusters[*]}{.name}{"\t"}{.cluster.server}{"\n"}{end}' |
31
+ while IFS=$'\t' read -r nom serveur; do
32
+ case "$serveur" in
33
+ https://127.0.0.1:* | https://localhost:*) ;;
34
+ *) continue ;;
35
+ esac
36
+ hote="${serveur#https://}"
37
+ hote="${hote%%:*}"
38
+ KUBECONFIG="$HOTE" kubectl config set-cluster "$nom" \
39
+ --server="https://host.docker.internal:${serveur##*:}" \
40
+ --tls-server-name="$hote" >/dev/null
41
+ done
42
+ fi
43
+
44
+ # Clusters kind qui ont survécu au redémarrage : contexte remis dans ~/.kube/config
45
+ # (le Docker interne peut mettre quelques secondes à démarrer)
46
+ for _ in 1 2 3 4 5 6 7 8 9 10; do docker info >/dev/null 2>&1 && break; sleep 1; done
47
+ choix="$(KUBECONFIG="$HOME/.kube/config" kubectl config current-context 2>/dev/null || true)"
48
+ for cluster in $(kind get clusters 2>/dev/null); do
49
+ kind export kubeconfig --name "$cluster" --kubeconfig "$HOME/.kube/config" >/dev/null 2>&1 || true
50
+ done
51
+
52
+ # Cluster actif : celui choisi avant (kubectl config use-context), sinon celui
53
+ # de l'hôte s'il en a un (current-context de hote.config), sinon kind
54
+ export KUBECONFIG="$HOME/.kube/config:$HOTE"
55
+ if [ -n "$choix" ] && kubectl config use-context "$choix" >/dev/null 2>&1; then
56
+ :
57
+ elif [ -f "$HOTE" ] && [ -n "$(KUBECONFIG="$HOTE" kubectl config current-context 2>/dev/null)" ]; then
58
+ KUBECONFIG="$HOME/.kube/config" kubectl config unset current-context >/dev/null
59
+ fi
60
+
61
+ # Clusters joignables, parmi ceux de l'hôte et ceux de kind
62
+ joignables=0
63
+ for contexte in $(kubectl config get-contexts -o name 2>/dev/null); do
64
+ if kubectl --context "$contexte" --request-timeout=3s get --raw /readyz >/dev/null 2>&1; then
65
+ echo "kube-config : cluster joignable : $contexte"
66
+ joignables=$((joignables + 1))
67
+ elif [[ "$contexte" == kind-* ]]; then
68
+ echo "kube-config : cluster kind en cours de démarrage : $contexte"
69
+ joignables=$((joignables + 1))
70
+ fi
71
+ done
72
+ # Module désactivé : le récapitulatif de devzone le signale
73
+ [ "$module" = on ] || exit 0
74
+ echo "kube-config : cluster actif : $(kubectl config current-context 2>/dev/null || echo aucun)"
75
+ if [ "$joignables" -eq 0 ]; then
76
+ echo "kube-config : aucun cluster joignable ; en créer un dans le conteneur : kind create cluster"
77
+ fi
78
+
79
+ # CPU/RAM dans k9s : metrics-server sur les clusters joignables qui ne l'ont pas
80
+ bash "$ICI/metrics-server.sh" || true
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env bash
2
+ # Installe metrics-server (CPU/RAM dans k9s, kubectl top) sur les clusters qui
3
+ # n'ont pas d'API Metrics. Docker Desktop et kind ne l'ont pas d'office.
4
+ # Usage : metrics-server.sh [contexte...] (défaut : clusters locaux joignables)
5
+ # --kubelet-insecure-tls : le kubelet de Docker Desktop et de kind a un
6
+ # certificat auto-signé, sans cette option le pod ne devient jamais Ready.
7
+ # Sortie en erreur si un contexte demandé est inconnu ou injoignable, ou si
8
+ # une installation échoue (kube-config.sh l'appelle avec || true).
9
+ set -euo pipefail
10
+
11
+ VERSION=v0.9.0
12
+ MANIFESTE="https://github.com/kubernetes-sigs/metrics-server/releases/download/${VERSION}/components.yaml"
13
+
14
+ mapfile -t connus < <(kubectl config get-contexts -o name 2>/dev/null || true)
15
+ demandes=$#
16
+ if [ "$demandes" -eq 0 ]; then
17
+ # Clusters locaux seulement : jamais d'install automatique sur un cluster
18
+ # distant de l'hôte (prod, staging…) ; pour un autre, le nommer en argument
19
+ mapfile -t contextes < <(printf '%s\n' ${connus[@]+"${connus[@]}"} |
20
+ grep -E '^(kind-.*|docker-desktop|rancher-desktop|orbstack|minikube)$' || true)
21
+ set -- ${contextes[@]+"${contextes[@]}"}
22
+ fi
23
+
24
+ code=0
25
+ joignables=0
26
+ for contexte in "$@"; do
27
+ if [ "$demandes" -gt 0 ] && ! printf '%s\n' ${connus[@]+"${connus[@]}"} | grep -qxF -- "$contexte"; then
28
+ echo "metrics-server : contexte inconnu : $contexte (voir kubectl config get-contexts)" >&2
29
+ code=1
30
+ continue
31
+ fi
32
+ k=(kubectl --context "$contexte" --request-timeout=5s)
33
+ if ! "${k[@]}" get --raw /readyz >/dev/null 2>&1; then
34
+ # Sans argument : kind peut être en cours de démarrage, ignoré
35
+ if [ "$demandes" -gt 0 ]; then
36
+ echo "metrics-server : cluster injoignable : $contexte" >&2
37
+ code=1
38
+ fi
39
+ continue
40
+ fi
41
+ joignables=$((joignables + 1))
42
+ if "${k[@]}" get apiservice v1beta1.metrics.k8s.io >/dev/null 2>&1; then
43
+ echo "metrics-server : déjà présent : $contexte"
44
+ continue
45
+ fi
46
+ if "${k[@]}" apply -f "$MANIFESTE" >/dev/null &&
47
+ "${k[@]}" -n kube-system patch deployment metrics-server --type=json \
48
+ -p '[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}]' >/dev/null &&
49
+ # Marque : make desinstaller ne retire que ce que devzone a installé
50
+ "${k[@]}" -n kube-system label deployment metrics-server devzone=installe --overwrite >/dev/null; then
51
+ echo "metrics-server : installé ($VERSION) : $contexte (métriques dans ~1 min)"
52
+ else
53
+ echo "metrics-server : échec de l'installation : $contexte" >&2
54
+ code=1
55
+ fi
56
+ done
57
+
58
+ if [ "$demandes" -eq 0 ] && [ "$joignables" -eq 0 ]; then
59
+ echo "metrics-server : aucun cluster local joignable ; après kind create cluster : bash .devcontainer/metrics-server.sh"
60
+ fi
61
+ exit "$code"
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env bash
2
+ # Étapes qui ne peuvent pas être dans l'image (Dockerfile) :
3
+ # - volumes montés au démarrage seulement
4
+ # - npm fourni par la feature node, ajoutée après le Dockerfile
5
+ set -euo pipefail
6
+
7
+ # Volumes nommés créés en root → rendre au user vscode
8
+ # (et ~/.config, créé par Docker pour monter ~/.config/opencode)
9
+ sudo chown -R vscode:vscode /home/vscode/.m2 /home/vscode/.local /home/vscode/.claude \
10
+ /home/vscode/.config/opencode /home/vscode/.config/gh /home/vscode/.config/git \
11
+ /home/vscode/.config/devzone
12
+ sudo chown vscode:vscode /home/vscode/.config
13
+
14
+ # Git : dépôts du conteneur déclarés sûrs (leur propriétaire peut différer de
15
+ # l'utilisateur qui lance git : volumes, Docker Desktop, outils lancés à part),
16
+ # et accès à GitHub par le jeton de gh, conservé dans son volume (https, même
17
+ # pour les remotes en git@github.com:, sans clé ssh à recopier)
18
+ # Réglages de la machine dans ~/.gitconfig du conteneur (recréé à chaque
19
+ # rebuild) : sans ce fichier, git config --global (et repowarden install)
20
+ # écriraient dans ~/.config/git/config, le volume de l'identité, où ils
21
+ # s'accumuleraient d'un rebuild à l'autre
22
+ touch "$HOME/.gitconfig"
23
+ # Volume touché par une version antérieure : seuls ces réglages en sont
24
+ # retirés, l'identité et tout autre réglage sont conservés
25
+ volume="$HOME/.config/git/config"
26
+ if [ -f "$volume" ]; then
27
+ retirer() { git config --file "$volume" --unset-all "$@" 2>/dev/null || true; }
28
+ retirer safe.directory '^/workspaces/devzone'
29
+ retirer credential.https://github.com.helper
30
+ retirer url.https://github.com/.insteadOf
31
+ retirer core.hooksPath 'repowarden'
32
+ retirer alias.cc 'repowarden'
33
+ retirer repowarden.lang
34
+ fi
35
+ git config --global --add safe.directory /workspaces/devzone
36
+ git config --global --add safe.directory '/workspaces/devzone/workspace/*'
37
+ git config --global --replace-all credential.https://github.com.helper ''
38
+ git config --global --add credential.https://github.com.helper '!gh auth git-credential'
39
+ git config --global url.https://github.com/.insteadOf git@github.com:
40
+
41
+ # repowarden, version figée (il installe des hooks git globaux) ; mettre à jour
42
+ # en changeant la version ici, puis Rebuild Container
43
+ npm install -g repowarden@4.9.1
44
+ repowarden install --global --lang fr
45
+
46
+ # Modules facultatifs (assistants IA, Kubernetes) : commande devzone, état
47
+ # gardé dans le volume devzone-config ; installe ce qui est actif
48
+ sudo ln -sf /workspaces/devzone/.devcontainer/devzone /usr/local/bin/devzone
49
+ devzone appliquer
50
+
51
+ # Ce qui reste à faire (identité git, GitHub, modules) : récapitulatif de
52
+ # devzone, affiché à chaque démarrage (demarrage.sh)
53
+
54
+ recap="java $(java -version 2>&1 | head -1 | cut -d'"' -f2), node $(node -v), python $(python3 --version | cut -d' ' -f2), repowarden $(repowarden --version)"
55
+ ! command -v claude >/dev/null || recap+=", claude $(claude --version | cut -d' ' -f1)"
56
+ ! command -v opencode >/dev/null || recap+=", opencode $(opencode --version)"
57
+ echo "devzone prêt : $recap"
package/.gitattributes ADDED
@@ -0,0 +1,5 @@
1
+ # Scripts lancés dans le conteneur Linux : fins de ligne LF même sur un
2
+ # checkout Windows (bash échoue sur les CRLF)
3
+ *.sh text eol=lf
4
+ Dockerfile text eol=lf
5
+ Makefile text eol=lf