mirror of
https://github.com/imjasonh/git-k8s
synced 2026-07-11 07:59:39 +00:00
Improve e2e smoke test with real git server and push controller exercise
Replace the stub smoke test (which only verified CRD creation) with a full end-to-end test that: - Deploys Gitea as an in-cluster git server (emptyDir, auto-install) - Initializes a test repository with an admin user and initial commit - Creates GitRepository, GitBranch, and GitPushTransaction CRDs - Verifies the push controller clones, pushes main to a new branch, and transitions the transaction to Succeeded - Verifies the controller updates the GitBranch CR's headCommit - Verifies the new branch actually exists on the git server Also fixes a bug in the push controller's resolveAuth: Secret data values are base64-encoded when accessed via the dynamic client, but were being used directly without decoding, causing authentication failures. https://claude.ai/code/session_01QfFzqKQUsxxBsiZUhuJ3pG
This commit is contained in:
parent
fe3fe95983
commit
aebe5c6c67
2 changed files with 204 additions and 6 deletions
193
.github/workflows/ci.yaml
vendored
193
.github/workflows/ci.yaml
vendored
|
|
@ -92,23 +92,208 @@ jobs:
|
|||
kubectl get crd gitpushtransactions.git-k8s.imjasonh.com
|
||||
kubectl get crd gitreposyncs.git-k8s.imjasonh.com
|
||||
|
||||
- name: Smoke test - create a GitRepository
|
||||
- name: Deploy Gitea git server
|
||||
run: |
|
||||
cat <<EOF | kubectl apply -f -
|
||||
cat <<'EOF' | kubectl apply -f -
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: gitea
|
||||
namespace: git-system
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: gitea
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: gitea
|
||||
spec:
|
||||
containers:
|
||||
- name: gitea
|
||||
image: gitea/gitea:1.21
|
||||
ports:
|
||||
- containerPort: 3000
|
||||
name: http
|
||||
env:
|
||||
- name: GITEA__database__DB_TYPE
|
||||
value: sqlite3
|
||||
- name: GITEA__security__INSTALL_LOCK
|
||||
value: "true"
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /api/v1/version
|
||||
port: 3000
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 256Mi
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
volumes:
|
||||
- name: data
|
||||
emptyDir: {}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: gitea
|
||||
namespace: git-system
|
||||
spec:
|
||||
selector:
|
||||
app: gitea
|
||||
ports:
|
||||
- port: 3000
|
||||
targetPort: 3000
|
||||
name: http
|
||||
EOF
|
||||
|
||||
- name: Wait for Gitea
|
||||
run: kubectl rollout status deployment/gitea -n git-system --timeout=120s
|
||||
|
||||
- name: Initialize Gitea
|
||||
run: |
|
||||
# Create admin user.
|
||||
kubectl exec -n git-system deploy/gitea -- \
|
||||
gitea admin user create \
|
||||
--admin \
|
||||
--username testadmin \
|
||||
--password testpassword123 \
|
||||
--email admin@test.local \
|
||||
--must-change-password=false
|
||||
|
||||
# Create test repository with an initial commit on main.
|
||||
kubectl exec -n git-system deploy/gitea -- \
|
||||
curl -sf -X POST http://localhost:3000/api/v1/user/repos \
|
||||
-H 'Content-Type: application/json' \
|
||||
-u testadmin:testpassword123 \
|
||||
-d '{"name":"test-repo","auto_init":true,"default_branch":"main"}'
|
||||
echo ""
|
||||
echo "Test repository created"
|
||||
|
||||
- name: Create Git credentials Secret
|
||||
run: |
|
||||
kubectl create secret generic gitea-creds \
|
||||
--namespace=default \
|
||||
--from-literal=username=testadmin \
|
||||
--from-literal=password=testpassword123
|
||||
|
||||
- name: Create GitRepository
|
||||
run: |
|
||||
cat <<'EOF' | kubectl apply -f -
|
||||
apiVersion: git-k8s.imjasonh.com/v1alpha1
|
||||
kind: GitRepository
|
||||
metadata:
|
||||
name: test-repo
|
||||
namespace: default
|
||||
spec:
|
||||
url: https://github.com/example/test.git
|
||||
url: http://gitea.git-system.svc.cluster.local:3000/testadmin/test-repo.git
|
||||
defaultBranch: main
|
||||
auth:
|
||||
secretRef:
|
||||
name: gitea-creds
|
||||
EOF
|
||||
kubectl get gitrepositories -A
|
||||
|
||||
- name: Create GitBranch
|
||||
run: |
|
||||
cat <<'EOF' | kubectl apply -f -
|
||||
apiVersion: git-k8s.imjasonh.com/v1alpha1
|
||||
kind: GitBranch
|
||||
metadata:
|
||||
name: test-repo-feature
|
||||
namespace: default
|
||||
spec:
|
||||
repositoryRef: test-repo
|
||||
branchName: feature-test
|
||||
EOF
|
||||
kubectl get gitbranches -A
|
||||
|
||||
- name: Push main to a new branch via GitPushTransaction
|
||||
run: |
|
||||
cat <<'EOF' | kubectl apply -f -
|
||||
apiVersion: git-k8s.imjasonh.com/v1alpha1
|
||||
kind: GitPushTransaction
|
||||
metadata:
|
||||
name: test-push
|
||||
namespace: default
|
||||
spec:
|
||||
repositoryRef: test-repo
|
||||
refSpecs:
|
||||
- source: refs/heads/main
|
||||
destination: refs/heads/feature-test
|
||||
EOF
|
||||
kubectl get gitpushtransactions -A
|
||||
|
||||
- name: Wait for push transaction to succeed
|
||||
run: |
|
||||
echo "Waiting for GitPushTransaction to complete..."
|
||||
for i in $(seq 1 60); do
|
||||
PHASE=$(kubectl get gitpushtransaction test-push -n default \
|
||||
-o jsonpath='{.status.phase}' 2>/dev/null)
|
||||
echo " attempt ${i}: phase=${PHASE:-Pending}"
|
||||
if [ "$PHASE" = "Succeeded" ]; then
|
||||
echo "Push transaction succeeded!"
|
||||
break
|
||||
elif [ "$PHASE" = "Failed" ]; then
|
||||
echo "Push transaction FAILED!"
|
||||
kubectl get gitpushtransaction test-push -n default -o yaml
|
||||
kubectl logs -n git-system deploy/push-controller --tail=100
|
||||
exit 1
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
PHASE=$(kubectl get gitpushtransaction test-push -n default \
|
||||
-o jsonpath='{.status.phase}')
|
||||
if [ "$PHASE" != "Succeeded" ]; then
|
||||
echo "Timed out waiting for push transaction (phase: ${PHASE:-empty})"
|
||||
kubectl logs -n git-system deploy/push-controller --tail=100
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Verify push transaction result
|
||||
run: |
|
||||
echo "=== GitPushTransaction status ==="
|
||||
kubectl get gitpushtransaction test-push -n default -o yaml
|
||||
|
||||
COMMIT=$(kubectl get gitpushtransaction test-push -n default \
|
||||
-o jsonpath='{.status.resultCommit}')
|
||||
echo "Result commit: $COMMIT"
|
||||
if [ -z "$COMMIT" ]; then
|
||||
echo "FAIL: resultCommit is empty"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Verify GitBranch was updated by controller
|
||||
run: |
|
||||
echo "=== GitBranch status ==="
|
||||
kubectl get gitbranch test-repo-feature -n default -o yaml
|
||||
|
||||
COMMIT=$(kubectl get gitbranch test-repo-feature -n default \
|
||||
-o jsonpath='{.status.headCommit}')
|
||||
echo "GitBranch headCommit: $COMMIT"
|
||||
if [ -z "$COMMIT" ]; then
|
||||
echo "FAIL: GitBranch headCommit was not updated by the controller"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Verify branch exists on git server
|
||||
run: |
|
||||
echo "Listing branches on Gitea..."
|
||||
kubectl exec -n git-system deploy/gitea -- \
|
||||
curl -sf http://localhost:3000/api/v1/repos/testadmin/test-repo/branches/feature-test \
|
||||
-u testadmin:testpassword123
|
||||
echo ""
|
||||
echo "Branch feature-test verified on git server!"
|
||||
|
||||
- name: Collect diagnostics
|
||||
if: ${{ failure() }}
|
||||
uses: chainguard-dev/actions/kind-diag@main
|
||||
with:
|
||||
artifact-name: kind-logs
|
||||
cluster-resources: nodes,namespaces,crds
|
||||
namespace-resources: pods,deployments,services
|
||||
namespace-resources: pods,deployments,services,gitrepositories,gitbranches,gitpushtransactions
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package push
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-git/go-git/v5"
|
||||
|
|
@ -160,9 +161,21 @@ func (r *Reconciler) resolveAuth(ctx context.Context, namespace string, repo *gi
|
|||
return nil, fmt.Errorf("reading secret data: found=%v err=%v", found, err)
|
||||
}
|
||||
|
||||
// Secret data values are base64-encoded in the API response when
|
||||
// accessed via the dynamic client (unlike the typed client which
|
||||
// decodes automatically into []byte fields).
|
||||
username, err := base64.StdEncoding.DecodeString(data["username"])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decoding username: %w", err)
|
||||
}
|
||||
password, err := base64.StdEncoding.DecodeString(data["password"])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decoding password: %w", err)
|
||||
}
|
||||
|
||||
return &http.BasicAuth{
|
||||
Username: data["username"],
|
||||
Password: data["password"],
|
||||
Username: string(username),
|
||||
Password: string(password),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue