diff --git a/docs/runbooks/opax-live-deploy.md b/docs/runbooks/opax-live-deploy.md index 6687c9f..f656989 100644 --- a/docs/runbooks/opax-live-deploy.md +++ b/docs/runbooks/opax-live-deploy.md @@ -97,4 +97,72 @@ Use one of these existing rollback methods: previously known good immutable digest. Use `./scripts/check-live-services.sh` to record the currently active revisions -and images before a release. \ No newline at end of file +and images before a release. + +--- + +## Appendix: `git-update.sh` Script + +### Hensikt og sikkerhetsmodell + +`scripts/git-update.sh` er en sikker wrapper for git-operasjoner mot prosjektets Gitea-repository, designet for å forhindre vanlige feil og håndheve beste praksis for versjonskontroll. + +### Kommandoer + +Scriptet bruker et subkommando-grensesnitt: + +#### **`./scripts/git-update.sh status`** + +Viser status for repositoryet. Dette er standardvalget hvis ingen subkommando gis. + +#### **`./scripts/git-update.sh commit [--allow-main] -m "" -- [...]`** + +Stager en eksplisitt liste filer, validerer, og kjører deretter en interaktiv `commit` og `push` i én operasjon. + +- **`--allow-main`**: Valgfritt flagg som må brukes for å commite direkte til `main`-branchen. +- **`-m ""`**: En obligatorisk commit-melding. +- **`-- `**: En eller flere filer som skal behandles. + +#### **`./scripts/git-update.sh push [--allow-main]`** + +Pusher en *allerede opprettet* lokal commit som ennå ikke er lastet opp til Gitea. + +### Sikkerhetsgarantier + +1. **Gitea-validering**: Scriptet verifiserer at `origin` peker til prosjektets godkjente Gitea-repository. Det vil nekte å kjøre hvis `origin` er GitHub eller en ukjent URL. +2. **Ingen Pre-staged Commits**: Scriptet avbryter hvis det finnes filer i "staging area" *før* `git add`-kommandoen kjøres. Dette forhindrer at utilsiktede endringer blir med i en commit. +3. **Eksplisitt filliste**: Kun filene som listes eksplisitt etter `--` blir lagt til i staging. Scriptet bruker aldri `git add .` eller `git add -A`. +4. **Whitespace-sjekker**: Før og etter staging kjøres `git diff --check` for å avdekke og stoppe ved whitespace-feil. +5. **Interaktiv bekreftelse**: Før en commit og push, vises en status over stagede filer, og brukeren må bekrefte med `y`. Hvis brukeren avbryter, forblir de eksplisitt stagede filene i staging area, men ingen commit eller push utføres. +6. **Beskyttelse av `main`**: Operasjoner (commit/push) mot `main`-branchen er blokkert med mindre det eksplisitte `--allow-main` flagget er brukt. +7. **Trygg Push**: Bruker `git push origin `. Bruker aldri `git push --force`. + +### Eksempler + +**Sjekk status:** + +```bash +./scripts/git-update.sh status +``` + +**Commit og push til en feature-branch:** + +```bash +./scripts/git-update.sh commit -m "feat: Add new script" -- \ + scripts/new-script.sh \ + docs/new-doc.md +``` + +**Push en allerede opprettet commit:** + +```bash +./scripts/git-update.sh push +``` + +**Avbrudd på grunn av pre-stagede endringer:** + +```text +FEIL: Repositoryet har allerede staged endringer. +Avbryter for å hindre at filer utenfor den eksplisitte fillisten blir committet. +Kjør: git diff --cached --name-status +``` \ No newline at end of file diff --git a/scripts/git-update.sh b/scripts/git-update.sh new file mode 100755 index 0000000..9082cda --- /dev/null +++ b/scripts/git-update.sh @@ -0,0 +1,166 @@ +#!/usr/bin/env bash +set -euo pipefail + +# En sikker wrapper for å adde, committe og pushe filer til Gitea. + +readonly REPO_ROOT="$(git rev-parse --show-toplevel)" +readonly ALLOWED_ORIGIN_CONTAINS="git.vauco.no/chris/OSVauco.git" + +error() { + echo "FEIL: $1" >&2 + exit 1 +} + +check_repository() { + local origin_url + origin_url="$(git remote get-url origin 2>/dev/null)" || + error "Fant ikke Git remote 'origin'." + + if [[ "${origin_url}" == *github.com* ]]; then + error "Remote 'origin' peker på GitHub. OSVauco bruker kun Gitea." + fi + + if [[ "${origin_url}" != *"${ALLOWED_ORIGIN_CONTAINS}"* ]]; then + error "Remote 'origin' er ikke godkjent Gitea-remote: ${origin_url}" + fi +} + +check_main_branch() { + local current_branch + current_branch="$(git rev-parse --abbrev-ref HEAD)" + if [[ "${current_branch}" == "main" ]]; then + error "Direkte operasjoner på 'main' krever '--allow-main' flagget." + fi +} + +handle_status() { + git status +} + +handle_commit() { + local allow_main=false + if [[ "${1:-}" == "--allow-main" ]]; then + allow_main=true + shift + fi + + if ! $allow_main; then + check_main_branch + fi + + if [[ $# -lt 4 || "$1" != "-m" || "$3" != "--" ]]; then + error "Bruk: commit [--allow-main] -m \"\" -- [...]" + fi + + local msg="$2" + shift 3 + local files=("$@") + + if [[ -z "${msg//[[:space:]]/}" ]]; then + error "Commit-meldingen kan ikke være tom." + fi + + if ! git diff --cached --quiet --exit-code; then + echo "FEIL: Repositoryet har allerede staged endringer." >&2 + echo "Avbryter for å hindre at filer utenfor den eksplisitte fillisten blir committet." >&2 + echo "Kjør: git diff --cached --name-status" >&2 + exit 1 + fi + + for file in "${files[@]}"; do + if [[ ! -e "${file}" ]] && ! git ls-files --error-unmatch -- "${file}" >/dev/null 2>&1; then + error "Filen finnes ikke og er ikke en Git-tracked fil: ${file}" + fi + local real_path + real_path="$(realpath -m -- "${file}")" + if [[ "${real_path}" != "${REPO_ROOT}" && "${real_path}" != "${REPO_ROOT}/"* ]]; then + error "Filen '${file}' er utenfor repository-roten." + fi + done + + echo "Kjører whitespace-sjekk før staging..." + git diff --check -- "${files[@]}" || error "Whitespace-feil funnet. Avbryter." + + git add -- "${files[@]}" + + if git diff --cached --quiet --exit-code; then + echo "Ingen endringer ble staged fra de oppgitte filene. Ingenting å committe." + exit 0 + fi + + echo "Kjører whitespace-sjekk etter staging..." + git diff --cached --check || error "Whitespace-feil funnet i staging. Avbryter." + + echo + echo "Følgende endringer vil bli committet:" + echo "------------------------------------" + git --no-pager diff --cached --name-status + echo "------------------------------------" + git --no-pager diff --cached --stat + echo "------------------------------------" + echo + + read -r -p "Commit og push de viste filene til Gitea? [y/N] " reply + if [[ ! "${reply}" =~ ^[Yy]$ ]]; then + echo "Avbrutt. Endringene er staged, men ikke committet." + exit 0 + fi + + git commit -m "${msg}" + echo "✅ Commit opprettet." + + echo "Pusher commit til Gitea..." + local current_branch + current_branch="$(git rev-parse --abbrev-ref HEAD)" + git push origin "${current_branch}" + echo "✅ Commit og push fullført." +} + +handle_push() { + local allow_main=false + + if [[ "${1:-}" == "--allow-main" ]]; then + allow_main=true + shift + fi + + if [[ "$#" -ne 0 ]]; then + error "Bruk: push [--allow-main]" + fi + + if ! $allow_main; then + check_main_branch + fi + + local current_branch + current_branch="$(git rev-parse --abbrev-ref HEAD)" + + echo "Pusher til origin/${current_branch}..." + git push origin "${current_branch}" + echo "✅ Push fullført." +} + +main() { + cd "${REPO_ROOT}" + check_repository + + local cmd=${1:-status} + shift || true + + case "${cmd}" in + status) + handle_status "$@" + ;; + commit) + handle_commit "$@" + ;; + push) + handle_push "$@" + ;; + *) + error "Ukjent kommando: '${cmd}'. Gyldige kommandoer er 'status', 'commit', 'push'." + ;; + esac +} + +main "$@" \ No newline at end of file