"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@oclif/core");
const nest_app_1 = require("../lib/nest-app");
const cli_ssh_service_1 = require("../services/cli-ssh.service");
const cli_observability_cluster_service_1 = require("../services/cli-observability-cluster.service");
class DiagOidc extends core_1.Command {
    async run() {
        const app = await (0, nest_app_1.getNestApp)();
        try {
            const ssh = app.get(cli_ssh_service_1.CliSshService);
            const obs = app.get(cli_observability_cluster_service_1.CliObservabilityClusterService);
            const cluster = await obs.getObservabilityCluster();
            if (!cluster?.masterIpAddress) {
                this.error('No cluster / master IP');
            }
            const ip = cluster.masterIpAddress;
            this.log('# Master IP: ' + ip);
            this.log('# nipHostnameToken: ' + JSON.stringify(cluster.nipHostnameToken));
            const opRepo = app.get((await Promise.resolve().then(() => __importStar(require('../lib/repositories/cli-operation.repository')))).CliOperationRepository);
            const ops = await opRepo.find({ where: { resourceId: cluster.id } });
            this.log('# Operations on cluster:');
            for (const op of ops) {
                this.log(`  ${op.id} type=${op.operationType} status=${op.status} step=${op.currentStepIndex}/${op.totalSteps} createdAt=${op.createdAt}`);
                if (op.status === 'FAILED' || op.status === 'IN_PROGRESS' || op.status === 'PENDING') {
                    this.log('    metadata=' + JSON.stringify(op.metadata).slice(0, 600));
                }
            }
            this.log('# Local cluster status: ' + cluster.status);
            const cmds = [
                ['ACME solver ingresses (k8s Ingress)', "kubectl -n flui-system get ingress 2>&1; echo ---; kubectl -n flui-system get ingress -o yaml 2>&1 | grep -E 'host:|path:|name:|number:|className' | head -40"],
                ['Traefik routers on :web', "TPOD=$(kubectl -n kube-system get pod -l app.kubernetes.io/name=traefik -o jsonpath='{.items[0].metadata.name}'); kubectl -n kube-system exec $TPOD -- wget -qO- http://localhost:9000/api/http/routers 2>/dev/null | head -c 4000; echo"],
                ['Traefik routers via host curl', "TIP=$(kubectl -n kube-system get pod -l app.kubernetes.io/name=traefik -o jsonpath='{.items[0].status.podIP}'); echo TIP=$TIP; curl -s --connect-timeout 5 http://$TIP:9000/api/http/routers > /tmp/routers.json 2>&1; head -c 200 /tmp/routers.json; echo; echo ---PARSE---; python3 -c 'import json; rs=json.load(open(\"/tmp/routers.json\")); [print(r.get(\"name\",\"?\"),\"|rule=\",r.get(\"rule\",\"\")[:80],\"|eps=\",r.get(\"entryPoints\",[]),\"|stat=\",r.get(\"status\",\"\"),\"|tls=\",bool(r.get(\"tls\")),\"|err=\",str(r.get(\"error\",\"\"))[:120]) for r in rs]' 2>&1 | head -40"],
                ['IngressClass + Traefik k8s ingress provider', "kubectl get ingressclass -o wide 2>&1; echo ---traefik-args; kubectl -n kube-system get pod -l app.kubernetes.io/name=traefik -o jsonpath='{.items[0].spec.containers[0].args}' 2>&1 | tr ',' '\\n' | grep -iE 'kubernetesingress|kubernetescrd|providers' | head -20"],
                ['Sleep 8 then retest :80 (Traefik reload)', "sleep 8; for h in app api auth; do echo --- $h; curl -sk --connect-timeout 5 -o /dev/null -w 'HTTP %{http_code}\\n' --resolve $h.royal-gecko-72.162.55.56.10.nip.io:80:162.55.56.10 http://$h.royal-gecko-72.162.55.56.10.nip.io/ ; done"],
                ['PATCH: drop tls + add web entrypoint to zitadel', "for ir in flui-api flui-web zitadel; do kubectl -n flui-system patch ingressroute $ir --type=json -p '[{\"op\":\"remove\",\"path\":\"/spec/tls\"}]' 2>&1 | head -1; done; kubectl -n flui-system patch ingressroute zitadel --type=json -p '[{\"op\":\"replace\",\"path\":\"/spec/entryPoints\",\"value\":[\"web\",\"websecure\"]}]'; sleep 5; echo ---test---; for h in app api auth; do curl -sk --connect-timeout 5 -o /dev/null -w \"$h=HTTP %{http_code}\\n\" --resolve $h.royal-gecko-72.162.55.56.10.nip.io:80:162.55.56.10 http://$h.royal-gecko-72.162.55.56.10.nip.io/; done"],
                ['Test ACME path before retry', "TOKEN=$(kubectl -n flui-system get challenge -o jsonpath='{.items[0].spec.token}'); HOST=$(kubectl -n flui-system get challenge -o jsonpath='{.items[0].spec.dnsName}'); echo TOKEN=${TOKEN:0:20}... HOST=$HOST; curl -sk --connect-timeout 5 -o /tmp/c -w 'HTTP %{http_code}\\n' --resolve $HOST:80:162.55.56.10 http://$HOST/.well-known/acme-challenge/$TOKEN; echo body_first50=$(head -c 50 /tmp/c)"],
                ['Force cert-manager retry (delete Order)', "kubectl -n flui-system delete order --all 2>&1; kubectl -n flui-system delete certificaterequest --all 2>&1; sleep 6; kubectl -n flui-system get challenge,order,certificaterequest 2>&1 | head"],
                ['PATCH: cert-manager hostAliases -> Traefik ClusterIP', "TIP=$(kubectl -n kube-system get svc traefik -o jsonpath='{.spec.clusterIP}'); echo TIP=$TIP; kubectl -n cert-manager patch deploy cert-manager --type=json -p '[{\"op\":\"add\",\"path\":\"/spec/template/spec/hostAliases\",\"value\":[{\"ip\":\"'$TIP'\",\"hostnames\":[\"app.royal-gecko-72.162.55.56.10.nip.io\",\"api.royal-gecko-72.162.55.56.10.nip.io\",\"auth.royal-gecko-72.162.55.56.10.nip.io\"]}]}]' 2>&1; kubectl -n cert-manager rollout status deploy/cert-manager --timeout=60s 2>&1 | tail -3"],
                ['Order invalid reason + restart cycle', "kubectl -n flui-system get order -o yaml 2>&1 | grep -A2 -E 'state:|reason:|message:' | head -40; echo ---deleting all + restart cert-manager---; kubectl -n flui-system delete order,certificaterequest,challenge --all 2>&1; kubectl -n flui-system delete certificate flui-system-tls 2>&1"],
                ['Recreate Certificate', "cat <<'YAML' | kubectl apply -f -\napiVersion: cert-manager.io/v1\nkind: Certificate\nmetadata:\n  name: flui-system-tls\n  namespace: flui-system\n  labels:\n    app.kubernetes.io/managed-by: flui-cloud\nspec:\n  secretName: flui-system-tls\n  issuerRef:\n    name: letsencrypt-production\n    kind: ClusterIssuer\n  dnsNames:\n    - auth.royal-gecko-72.162.55.56.10.nip.io\n    - api.royal-gecko-72.162.55.56.10.nip.io\n    - app.royal-gecko-72.162.55.56.10.nip.io\nYAML\nsleep 10; kubectl -n flui-system get challenge,order 2>&1 | head"],
                ['Wait 25s then check', "sleep 25; kubectl -n flui-system get certificate,secret/flui-system-tls,challenge 2>&1"],
                ['Cert challenges + Certificate after fix', "kubectl -n flui-system get certificate flui-system-tls -o jsonpath='{.status.conditions[*].message}' 2>&1; echo; kubectl -n flui-system get challenge -o wide 2>&1 | head"],
                ['external curl :80 to ACME path', "for h in app api auth; do echo --- $h; curl -sk --connect-timeout 6 -o /dev/null -w 'HTTP %{http_code} loc=%{redirect_url}\\n' --resolve $h.royal-gecko-72.162.55.56.10.nip.io:80:162.55.56.10 http://$h.royal-gecko-72.162.55.56.10.nip.io/.well-known/acme-challenge/test 2>&1; done"],
                ['external curl :80 root', "for h in app api auth; do echo --- $h; curl -sk --connect-timeout 6 -o /dev/null -w 'HTTP %{http_code} loc=%{redirect_url}\\n' --resolve $h.royal-gecko-72.162.55.56.10.nip.io:80:162.55.56.10 http://$h.royal-gecko-72.162.55.56.10.nip.io/ 2>&1; done"],
                ['ACME solver ingresses', "kubectl -n flui-system get ingress 2>&1; echo ---; kubectl -n flui-system get ingress -o yaml 2>&1 | grep -E 'host:|path:|backend:|service:|name:|number:|class:' | head -50"],
                ['HTTP-01 self-check from cm pod', "CMP=$(kubectl -n cert-manager get pod -l app=cert-manager -o jsonpath='{.items[0].metadata.name}'); echo CMP=$CMP; for h in app api auth; do echo --- $h; kubectl -n cert-manager exec $CMP -- wget --spider --timeout=8 -S http://${h}.royal-gecko-72.162.55.56.10.nip.io/ 2>&1 | tail -10; done"],
                ['HTTP-01 self-check via local nginx-style', "CHALLENGE=$(kubectl -n flui-system get challenge -o jsonpath='{.items[0].spec.token}'); echo TOKEN=$CHALLENGE; CMP=$(kubectl -n cert-manager get pod -l app=cert-manager -o jsonpath='{.items[0].metadata.name}'); kubectl -n cert-manager exec $CMP -- wget -qO- --timeout=8 http://app.royal-gecko-72.162.55.56.10.nip.io/.well-known/acme-challenge/$CHALLENGE 2>&1 | head -5; echo ---; kubectl -n cert-manager exec $CMP -- wget -S --timeout=8 -O /dev/null http://162.55.56.10/.well-known/acme-challenge/$CHALLENGE 2>&1 | tail -8"],
                ['cert-manager Certificate', "kubectl -n flui-system get certificate -o wide 2>&1; echo ---; kubectl -n flui-system describe certificate 2>&1 | tail -50"],
                ['cert-manager Order/Challenge', "kubectl -n flui-system get order,challenge -o wide 2>&1; echo ---; kubectl -n flui-system describe challenge 2>&1 | tail -50"],
                ['cert-manager logs', "kubectl -n cert-manager logs -l app=cert-manager --tail=80 2>&1 | grep -iE 'error|fail|warn|royal-gecko' | tail -30"],
                ['ClusterIssuer', "kubectl get clusterissuer 2>&1"],
                ['placeholder',
                    'noop'],
                ['Traefik pod / svc', "kubectl -n kube-system get pods -l app.kubernetes.io/name=traefik -o wide 2>&1; echo; kubectl -n kube-system get svc traefik 2>&1"],
                ['Traefik logs (last 80, errors)', "kubectl -n kube-system logs -l app.kubernetes.io/name=traefik --tail=200 2>&1 | grep -iE 'error|fail|warn' | tail -40"],
                ['IngressRoutes flui-system', "kubectl -n flui-system get ingressroute -o wide 2>&1"],
                ['flui-system pods', "kubectl -n flui-system get pods 2>&1"],
                ['flui-system services', "kubectl -n flui-system get svc 2>&1"],
                ['flui-system-tls secret', "kubectl -n flui-system get secret flui-system-tls -o yaml 2>&1 | grep -E 'tls.crt|tls.key|name:' | head -10; echo ---; kubectl -n flui-system get secret flui-system-tls -o jsonpath='{.data.tls\\.crt}' 2>/dev/null | base64 -d | openssl x509 -noout -subject -issuer -dates 2>&1 | head"],
                ['IngressRoute for app/api/auth detail', "for n in 09-flui-api 10-flui-web 11-zitadel; do echo '=== '$n; kubectl -n flui-system get ingressroute -o yaml | grep -E 'host\\(|Host\\(|tls:|secretName' | head -20; done; kubectl -n flui-system get ingressroute -o yaml | grep -E 'match:|host:' | head -30"],
                ['curl from inside cluster (Traefik svc IP)', "TIP=$(kubectl -n kube-system get svc traefik -o jsonpath='{.spec.clusterIP}'); echo TIP=$TIP; for h in app.royal-gecko-72.162.55.56.10.nip.io api.royal-gecko-72.162.55.56.10.nip.io auth.royal-gecko-72.162.55.56.10.nip.io; do echo --- $h ---; curl -sk --connect-timeout 5 -o /dev/null -w 'HTTP %{http_code}\\n' -H \"Host: $h\" https://$TIP/; done"],
            ];
            const _allCmds = [
                ['OIDC_AUDIENCE in flui-secrets', "kubectl -n flui-system get secret flui-secrets -o jsonpath='{.data.OIDC_AUDIENCE}' | base64 -d; echo"],
                ['OIDC_ISSUER in flui-api-config', "kubectl -n flui-system get cm flui-api-config -o jsonpath='{.data.OIDC_ISSUER}'; echo"],
                ['OIDC_CLI_CLIENT_ID in flui-api-config', "kubectl -n flui-system get cm flui-api-config -o jsonpath='{.data.OIDC_CLI_CLIENT_ID}'; echo"],
                ['oidcClientId in flui-web-config', "kubectl -n flui-system get cm flui-web-config -o jsonpath='{.data.config\\.json}'; echo"],
                ['flui-api OIDC log lines', "kubectl -n flui-system logs deploy/flui-api --tail=400 2>/dev/null | grep -iE 'oidc|bootstrap|zitadel' | tail -40 || echo '(no matches)'"],
                ['/var/log/flui-oidc-bootstrap.log tail', "test -f /var/log/flui-oidc-bootstrap.log && tail -80 /var/log/flui-oidc-bootstrap.log || echo '(file missing)'"],
                ['Zitadel pod status', "kubectl -n flui-system get pods 2>&1 | grep -i zitadel"],
                ['Zitadel ExternalDomain', "for cm in $(kubectl -n flui-system get cm -o name | grep -i zitadel); do echo --- $cm ---; kubectl -n flui-system get $cm -o yaml | grep -iE 'external|domain' | head -10; done"],
                ['flui-api pod -> Zitadel via tokenized Host', "POD=$(kubectl -n flui-system get pod -l app=flui-api -o jsonpath='{.items[0].metadata.name}'); ZDOM=$(kubectl -n flui-system get cm flui-api-config -o jsonpath='{.data.OIDC_ISSUER}' | sed 's|https://||'); PAT=$(kubectl -n flui-system get secret flui-secrets -o jsonpath='{.data.ZITADEL_SERVICE_ACCOUNT_PAT}' | base64 -d); echo POD=$POD; echo ZDOM_used=$ZDOM; kubectl -n flui-system exec $POD -c flui-api -- sh -c \"curl -s -o /tmp/o -w 'HTTP %{http_code}\\n' -H 'Host: $ZDOM' -H 'Authorization: Bearer $PAT' http://zitadel.flui-system.svc.cluster.local:8080/auth/v1/users/me; head -c 200 /tmp/o; echo; echo --no-host--; curl -s -o /tmp/o -w 'HTTP %{http_code}\\n' -H 'Authorization: Bearer $PAT' http://zitadel.flui-system.svc.cluster.local:8080/auth/v1/users/me; head -c 250 /tmp/o; echo\" 2>&1"],
                ['axios from flui-api pod: capital Host vs lowercase host', "POD=$(kubectl -n flui-system get pod -l app=flui-api -o jsonpath='{.items[0].metadata.name}'); ZDOM=$(kubectl -n flui-system get cm flui-api-config -o jsonpath='{.data.OIDC_ISSUER}' | sed 's|https://||'); PAT=$(kubectl -n flui-system get secret flui-secrets -o jsonpath='{.data.ZITADEL_SERVICE_ACCOUNT_PAT}' | base64 -d); kubectl -n flui-system exec $POD -c flui-api -- node -e \"const a=require('axios');(async()=>{for (const k of ['Host','host']){try{const r=await a.get('http://zitadel.flui-system.svc.cluster.local:8080/auth/v1/users/me',{headers:{[k]:'$ZDOM',Authorization:'Bearer $PAT'},validateStatus:()=>true});console.log(k+'=>HTTP '+r.status+' '+JSON.stringify(r.data).slice(0,100));}catch(e){console.log(k+'=>ERR '+e.message)}}})();\" 2>&1"],
                ['find postgres pod', "kubectl -n flui-system get pods -o wide | grep -iE 'postgres|sql' | head"],
                ['flui-api DB env', "POD=$(kubectl -n flui-system get pod -l app=flui-api -o jsonpath='{.items[0].metadata.name}'); kubectl -n flui-system exec $POD -c flui-api -- sh -c 'echo DB_USERNAME=$DB_USERNAME; echo DB_NAME=$DB_NAME; echo DB_HOST=$DB_HOST'"],
                ['cluster row (in-cluster DB)', "kubectl -n flui-system exec postgres-0 -- psql -U fluicloud -d fluicloud -tAc 'SELECT id, name, \"masterIpAddress\", \"nipHostnameToken\", \"clusterType\" FROM infrastructure_clusters;' 2>&1 | head"],
                ['flui-api PAT in env vs in PVC', "POD=$(kubectl -n flui-system get pod -l app=flui-api -o jsonpath='{.items[0].metadata.name}'); kubectl -n flui-system exec $POD -c flui-api -- sh -c 'echo ENV_PAT_LEN=${#ZITADEL_SERVICE_ACCOUNT_PAT}; echo ENV_PAT_HEAD=${ZITADEL_SERVICE_ACCOUNT_PAT:0:8}'; SECRET_PAT=$(kubectl -n flui-system get secret flui-secrets -o jsonpath='{.data.ZITADEL_SERVICE_ACCOUNT_PAT}' | base64 -d); echo SECRET_PAT_LEN=${#SECRET_PAT}; echo SECRET_PAT_HEAD=${SECRET_PAT:0:8}; PVC_PAT=$(kubectl -n flui-system exec deploy/zitadel -- cat /pvc/flui-api-system.pat 2>/dev/null || echo none); echo PVC_PAT_LEN=${#PVC_PAT}; echo PVC_PAT_HEAD=${PVC_PAT:0:8}"],
                ['Zitadel /auth/v1/users/me (what verifyPat hits)', "PAT=$(kubectl -n flui-system get secret flui-secrets -o jsonpath='{.data.ZITADEL_SERVICE_ACCOUNT_PAT}' | base64 -d); ZDOM=$(kubectl -n flui-system get cm flui-api-config -o jsonpath='{.data.OIDC_ISSUER}' | sed 's|https://||'); echo via_internal_dns:; curl -s -o /tmp/out -w 'HTTP %{http_code}\\n' -H \"Host: $ZDOM\" -H \"Authorization: Bearer $PAT\" http://zitadel.flui-system.svc.cluster.local:8080/auth/v1/users/me; head -c 300 /tmp/out; echo; echo via_clusterip:; ZSVC=$(kubectl -n flui-system get svc zitadel -o jsonpath='{.spec.clusterIP}'):8080; curl -s -o /tmp/out -w 'HTTP %{http_code}\\n' -H \"Host: $ZDOM\" -H \"Authorization: Bearer $PAT\" http://$ZSVC/auth/v1/users/me; head -c 300 /tmp/out; echo"],
            ];
            for (const [label, cmd] of cmds) {
                this.log('\n=== ' + label + ' ===');
                try {
                    const out = await ssh.sshExec(ip, cmd);
                    this.log(out.trim());
                }
                catch (e) {
                    this.log('ERR: ' + (e?.message ?? String(e)));
                }
            }
        }
        finally {
            await (0, nest_app_1.closeNestApp)();
        }
    }
}
DiagOidc.description = 'Internal diag: OIDC bootstrap state';
DiagOidc.hidden = true;
exports.default = DiagOidc;
