From 1bfd03226b4efb94994556273e5111806d139140 Mon Sep 17 00:00:00 2001 From: Petr Nyc Date: Fri, 12 Jun 2026 13:13:07 +0200 Subject: [PATCH] panic commit --- .codex-sso/config.toml | 98 +++- .spacemacs | 74 +-- .zshenv | 1 + .zshrc | 16 + bin/codex-auth-common.zsh | 5 +- bin/codex-devops-auth.sh | 11 +- bin/codex-sso | 1 + ...saservicedev-image-to-daaspreproduction.sh | 465 ++++++++++++++++++ 8 files changed, 608 insertions(+), 63 deletions(-) create mode 100755 bin/copy-desktopasaservicedev-image-to-daaspreproduction.sh diff --git a/.codex-sso/config.toml b/.codex-sso/config.toml index 9234ecf..6d502ed 100644 --- a/.codex-sso/config.toml +++ b/.codex-sso/config.toml @@ -25,12 +25,13 @@ trust_level = "trusted" sandbox_mode = "workspace-write" personality = "pragmatic" -model_reasoning_effort = "xhigh" +model_reasoning_effort = "high" notify = ["/Users/jetpac/.codex-sso/computer-use/Codex Computer Use.app/Contents/SharedSupport/SkyComputerUseClient.app/Contents/MacOS/SkyComputerUseClient", "turn-ended"] # approvals_reviewer = "guardian_subagent" approvals_reviewer = "auto_review" +plan_mode_reasoning_effort = "xhigh" [features] @@ -320,6 +321,9 @@ approval_mode = "approve" [mcp_servers.mcp_shepherd.tools.shepherd_get_release_target_errors] approval_mode = "approve" +[mcp_servers.mcp_shepherd.tools.shepherd_generate_plan_shape] +approval_mode = "approve" + [mcp_servers.grt] command = "/Users/jetpac/.codex-sso/bin/grt-mcp" startup_timeout_sec = 30.0 @@ -333,6 +337,9 @@ approval_mode = "approve" [mcp_servers.grt.tools."grt.search_entries"] approval_mode = "approve" +[mcp_servers.grt] +GRT_ENABLE_WRITE_TOOLS = "true" + [mcp_servers.webrti] command = "/Users/jetpac/.codex-sso/bin/webrti-mcp" startup_timeout_sec = 30.0 @@ -1005,6 +1012,21 @@ trust_level = "trusted" [projects."/Users/jetpac/Documents/akidr-ips"] trust_level = "trusted" +[projects."/Users/jetpac/.codex-sso-test"] +trust_level = "trusted" + +[projects."/Users/jetpac/Documents/OSD/SVOS_presentation"] +trust_level = "trusted" + +[projects."/Users/jetpac/Documents/webrti"] +trust_level = "trusted" + +[projects."/Users/jetpac/PycharmProjects/on-sru/solaris/akidr"] +trust_level = "trusted" + +[projects."/Users/jetpac/Documents/ips"] +trust_level = "trusted" + [marketplaces.openai-bundled] last_updated = "2026-05-28T10:46:49Z" source_type = "local" @@ -1241,6 +1263,36 @@ approval_mode = "approve" [mcp_servers.mcp_gateway.tools.bitbucket__get_reviews] approval_mode = "approve" +[mcp_servers.mcp_gateway.tools.buildservice__buildservice_list_projects_by_team] +approval_mode = "approve" + +[mcp_servers.mcp_gateway.tools.bitbucket__get_file_content] +approval_mode = "approve" + +[mcp_servers.mcp_gateway.tools.bitbucket__get_pull_request_comment] +approval_mode = "approve" + +[mcp_servers.mcp_gateway.tools.bitbucket__get_pull_request] +approval_mode = "approve" + +[mcp_servers.mcp_gateway.tools.bitbucket__browse_repository] +approval_mode = "approve" + +[mcp_servers.mcp_gateway.tools.jira__jira_get_project_components] +approval_mode = "approve" + +[mcp_servers.mcp_gateway.tools.devops__get_shepherd_terraform_resource_metadata] +approval_mode = "approve" + +[mcp_servers.mcp_gateway.tools.devops__get_shepherd_terraform_data_source_metadata] +approval_mode = "approve" + +[mcp_servers.mcp_gateway.tools.devops__list_shepherd_terraform_object_metadata] +approval_mode = "approve" + +[mcp_servers.mcp_gateway.tools.devops__list_shepherd_release_changes] +approval_mode = "approve" + [mcp_servers.node_repl] args = [] command = "/Applications/Codex.app/Contents/Resources/node_repl" @@ -1258,30 +1310,30 @@ BROWSER_USE_MARKETPLACE_NAME = "openai-bundled" NODE_REPL_UNTRUSTED_ENV_ALLOWLIST = "BROWSER_USE_MARKETPLACE_NAME" CODEX_CLI_PATH = "/Applications/Codex.app/Contents/Resources/codex" -[mcp_servers.remote_ssh] -command = "/Users/jetpac/.codex-sso/remote-ssh-mcp/node_modules/.bin/tsx" -args = ["/Users/jetpac/.codex-sso/remote-ssh-mcp/src/index.ts"] -startup_timeout_sec = 30.0 -tool_timeout_sec = 600.0 -default_tools_approval_mode = "approve" -env_vars = ["SSH_AUTH_SOCK"] +# [mcp_servers.remote_ssh] +# command = "/Users/jetpac/.codex-sso/remote-ssh-mcp/node_modules/.bin/tsx" +# args = ["/Users/jetpac/.codex-sso/remote-ssh-mcp/src/index.ts"] +# startup_timeout_sec = 30.0 +# tool_timeout_sec = 600.0 +# default_tools_approval_mode = "approve" +# env_vars = ["SSH_AUTH_SOCK"] -[mcp_servers.remote_ssh.env] -NODE_NO_WARNINGS = "1" +# [mcp_servers.remote_ssh.env] +# NODE_NO_WARNINGS = "1" -[mcp_servers.remote_ssh.tools.remote_ssh_run] -approval_mode = "approve" +# [mcp_servers.remote_ssh.tools.remote_ssh_run] +# approval_mode = "approve" -[mcp_servers.local_exec] -command = "/Users/jetpac/.codex-sso/local-exec-mcp/node_modules/.bin/tsx" -args = ["/Users/jetpac/.codex-sso/local-exec-mcp/src/index.ts"] -startup_timeout_sec = 30.0 -tool_timeout_sec = 3600.0 -default_tools_approval_mode = "approve" -env_vars = ["PATH", "HOME", "USER", "SHELL", "SSH_AUTH_SOCK"] +# [mcp_servers.local_exec] +# command = "/Users/jetpac/.codex-sso/local-exec-mcp/node_modules/.bin/tsx" +# args = ["/Users/jetpac/.codex-sso/local-exec-mcp/src/index.ts"] +# startup_timeout_sec = 30.0 +# tool_timeout_sec = 3600.0 +# default_tools_approval_mode = "approve" +# env_vars = ["PATH", "HOME", "USER", "SHELL", "SSH_AUTH_SOCK"] -[mcp_servers.local_exec.env] -NODE_NO_WARNINGS = "1" +# [mcp_servers.local_exec.env] +# NODE_NO_WARNINGS = "1" -[mcp_servers.local_exec.tools.local_exec_run] -approval_mode = "approve" +# [mcp_servers.local_exec.tools.local_exec_run] +# approval_mode = "approve" diff --git a/.spacemacs b/.spacemacs index 03882db..25f7ed1 100644 --- a/.spacemacs +++ b/.spacemacs @@ -32,7 +32,8 @@ This function should only modify configuration layer settings." ;; List of configuration layers to load. dotspacemacs-configuration-layers - '(typescript + '(graphviz + typescript windows-scripts swift multiple-cursors ;; https://www.spacemacs.org/layers/+misc/multiple-cursors/README.html#key-bindings @@ -78,6 +79,7 @@ This function should only modify configuration layer settings." org-enable-jira-support t jiralib-url "https://jira.oci.oraclecorp.com" jiralib-target-api-version 2 + org-default-notes-file "~/Documents/org/inbox.org" ;; org-enable-roam-support t ;; org-enable-roam-ui t ;; org-roam-completion-everywhere t @@ -996,10 +998,11 @@ before packages are loaded." (setq org-directory "~/Documents/org") - (setq org-default-notes-file "~/Documents/org/inbox.org") - + ;; (setq org-default-notes-file "~/Documents/org/inbox.org") (setq org-duration-format 'h:mm) + + ;; ;; ================================================================================ ;; ;; config for org-caldav for my nextcloud installation ;; ;; not working to my satisfaction yet - only configured for not used files @@ -1382,8 +1385,7 @@ This function is called at the very end of Spacemacs initialization." ("Solaris" . "tag:solaris") ("OCI" - . "tag:oci") - ) + . "tag:oci")) :filter "date:1/1/2026.. and (tag:important and tag:action)" :show-empty-searches @@ -1401,18 +1403,15 @@ This function is called at the very end of Spacemacs initialization." . "tag:announcement") ("Deployment Calendar events" . "tag:calendar") - ("SGD" . "tag:sgd") - ) + ("SGD" . "tag:sgd")) :filter "tag:osd and date:12/1/2025.. and (tag:unread or tag:important or tag:action)" :show-empty-searches nil) (notmuch-hello-insert-searches "Active dev projects needing focus" - ( - ("Linux images" . "tag:linux-images") - ("AK IPS delivery" . "tag:ak-ips or tag:akidr-ips") - ) - ) + (("Linux images" . "tag:linux-images") + ("AK IPS delivery" + . "tag:ak-ips or tag:akidr-ips"))) (notmuch-hello-insert-searches "Solaris Focused" (("Solaris" @@ -1537,31 +1536,32 @@ This function is called at the very end of Spacemacs initialization." farmhouse-themes fish-mode flatland-theme flatui-theme flx-ido flycheck forge frame-local gandalf-theme ggtags gh-md ghub git-link git-messenger git-modes git-timemachine gitignore-templates gntp gnuplot golden-ratio - google-translate gotham-theme grandshell-theme grizzl groovy-imports - groovy-mode gruber-darker-theme gruvbox-theme haml-mode hc-zenburn-theme - hcl-mode helm helm-ag helm-c-yasnippet helm-comint helm-company - helm-css-scss helm-descbinds helm-git-grep helm-ls-git helm-lsp helm-make - helm-mode-manager helm-notmuch helm-org helm-org-rifle helm-projectile - helm-purpose helm-pydoc helm-swoop helm-themes helm-xref hemisu-theme - heroku-theme hide-comnt hierarchy highlight-indentation highlight-numbers - highlight-parentheses hl-todo holy-mode htmlize hungry-delete hybrid-mode - impatient-mode import-js importmagic indent-guide info+ inkpot-theme - insert-shebang inspector ir-black-theme jazz-theme jbeans-theme js-doc - js2-mode js2-refactor json-mode json-navigator json-reformat - json-snatcher kaolin-themes light-soap-theme link-hint live-py-mode - livid-mode load-env-vars log4e lorem-ipsum lsp-docker lsp-mode - lsp-origami lsp-pyright lsp-treemacs lsp-ui lush-theme macrostep - madhat2r-theme magit magit-section markdown-mode markdown-toc - material-theme minimal-theme modus-themes moe-theme molokai-theme - monochrome-theme monokai-theme multi-line multi-term multi-vterm - multiple-cursors mustang-theme nameless naquadah-theme nginx-mode - noctilux-theme nodejs-repl nose notmuch npm-mode obsidian-theme - occidental-theme ol-notmuch oldlace-theme omtose-phellack-themes - open-junk-file org-alert org-caldav org-category-capture org-cliplink - org-contrib org-download org-jira org-mac-link org-mime org-msg - org-pomodoro org-present org-project-capture org-projectile org-rich-yank - org-superstar organic-green-theme orgit orgit-forge origami overseer - ox-jira ox-twbs pandoc-mode paradox password-generator pcache pcre2el + google-translate gotham-theme grandshell-theme graphviz-dot-mode grizzl + groovy-imports groovy-mode gruber-darker-theme gruvbox-theme haml-mode + hc-zenburn-theme hcl-mode helm helm-ag helm-c-yasnippet helm-comint + helm-company helm-css-scss helm-descbinds helm-git-grep helm-ls-git + helm-lsp helm-make helm-mode-manager helm-notmuch helm-org helm-org-rifle + helm-projectile helm-purpose helm-pydoc helm-swoop helm-themes helm-xref + hemisu-theme heroku-theme hide-comnt hierarchy highlight-indentation + highlight-numbers highlight-parentheses hl-todo holy-mode htmlize + hungry-delete hybrid-mode impatient-mode import-js importmagic + indent-guide info+ inkpot-theme insert-shebang inspector ir-black-theme + jazz-theme jbeans-theme js-doc js2-mode js2-refactor json-mode + json-navigator json-reformat json-snatcher kaolin-themes light-soap-theme + link-hint live-py-mode livid-mode load-env-vars log4e lorem-ipsum + lsp-docker lsp-mode lsp-origami lsp-pyright lsp-treemacs lsp-ui + lush-theme macrostep madhat2r-theme magit magit-section markdown-mode + markdown-toc material-theme minimal-theme modus-themes moe-theme + molokai-theme monochrome-theme monokai-theme multi-line multi-term + multi-vterm multiple-cursors mustang-theme nameless naquadah-theme + nginx-mode noctilux-theme nodejs-repl nose notmuch npm-mode + obsidian-theme occidental-theme ol-notmuch oldlace-theme + omtose-phellack-themes open-junk-file org-alert org-caldav + org-category-capture org-cliplink org-contrib org-download org-jira + org-mac-link org-mime org-msg org-pomodoro org-present + org-project-capture org-projectile org-rich-yank org-superstar + organic-green-theme orgit orgit-forge origami overseer ox-jira ox-twbs + pandoc-mode paradox password-generator pcache pcre2el phoenix-dark-mono-theme phoenix-dark-pink-theme pip-requirements pipenv pippel planet-theme poetry popwin pos-tip powershell prettier-js professional-theme pug-mode purple-haze-theme py-isort pydoc pyenv-mode diff --git a/.zshenv b/.zshenv index 3386aea..02ffcd8 100644 --- a/.zshenv +++ b/.zshenv @@ -7,3 +7,4 @@ alias config='/usr/bin/git --git-dir=$HOME/.cfg/ --work-tree=$HOME' export seznam6='2a02:598:2::1222' export OPENAI_API_KEY='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' +export BITBUCKET_TOKEN='NzQ0MDE3NjEzNDE1Oh6PpMt8Rl+a569vzoPOfCRJ+Kwt' diff --git a/.zshrc b/.zshrc index 431016a..e5a095b 100644 --- a/.zshrc +++ b/.zshrc @@ -22,6 +22,7 @@ fi set -o vi export ZSH="$HOME/.oh-my-zsh" +ZSH_CUSTOM="${ZSH_CUSTOM:-$ZSH/custom}" if [[ "$_profile_terminal" == 1 ]]; then ZSH_THEME="powerlevel10k/powerlevel10k" else @@ -52,6 +53,7 @@ plugins=( urltools history aliases + dircycle ) _profile_add_plugin() { @@ -189,6 +191,20 @@ if [[ -n ${commands[kubectl]} ]]; then fi if [[ "$OSTYPE" == darwin* ]]; then + + # add tokens to keychain: + # security add-generic-password \ + # -a "$USER" \ + # -s "BITBUCKET_TOKEN" \ + # -w "" + # -U + + keychain_token() { + security find-generic-password -s "$1" -w + } + + export BITBUCKET_TOKEN=$(keychain_token BITBUCKET_TOKEN) + export LSCOLORS=gxfxbEaEBxxEhEhBaDaCaD export MANPAGER='col -bx | view -c ":set ft=man nonu nolist nomod nolist" -' fi diff --git a/bin/codex-auth-common.zsh b/bin/codex-auth-common.zsh index c144414..53764e7 100644 --- a/bin/codex-auth-common.zsh +++ b/bin/codex-auth-common.zsh @@ -173,7 +173,10 @@ codex_auth_prepare_codex_auth() { fi set +e - CODEX_DEVOPS_AUTH_ENV_OUT="${CODEX_AUTH_COMMON_AUTH_ENV_FILE}" "${CODEX_DEVOPS_AUTH_SCRIPT}" + CODEX_DEVOPS_AUTH_ENV_OUT="${CODEX_AUTH_COMMON_AUTH_ENV_FILE}" \ + TOKEN_STRICT_HOST_KEY_CHECKING="${CODEX_AUTH_TOKEN_STRICT_HOST_KEY_CHECKING:-no}" \ + TOKEN_USER_KNOWN_HOSTS_FILE="${CODEX_AUTH_TOKEN_USER_KNOWN_HOSTS_FILE:-/dev/null}" \ + "${CODEX_DEVOPS_AUTH_SCRIPT}" local auth_rc=$? set -e diff --git a/bin/codex-devops-auth.sh b/bin/codex-devops-auth.sh index 0ec3990..98b1936 100755 --- a/bin/codex-devops-auth.sh +++ b/bin/codex-devops-auth.sh @@ -6,6 +6,8 @@ PKCS11_LIB="${PKCS11_LIB:-/usr/local/lib/opensc-pkcs11.so}" YUBIKEY_PIN_FILE="${YUBIKEY_PIN_FILE:-/tmp/pass}" TOKEN_HOST="${TOKEN_HOST:-operator-access-token.svc.ad1.r2}" SSH_CONFIG_FILE="${SSH_CONFIG_FILE:-$HOME/.ssh/config.oci}" +TOKEN_STRICT_HOST_KEY_CHECKING="${TOKEN_STRICT_HOST_KEY_CHECKING:-no}" +TOKEN_USER_KNOWN_HOSTS_FILE="${TOKEN_USER_KNOWN_HOSTS_FILE:-/dev/null}" OCI_BIN="${OCI_BIN:-/opt/homebrew/bin/oci}" OCI_SESSION_REGION="${OCI_SESSION_REGION:-us-chicago-1}" OCI_PROFILE_NAME="${OCI_PROFILE_NAME:-MCP_GW_DEFAULT}" @@ -376,7 +378,7 @@ quiet_proxy_command() { proxy_ssh_prefix() { local ssh_bin="$1" - local prefix="${ssh_bin} -F ${(q)SSH_CONFIG_FILE} -o LogLevel=ERROR" + local prefix="${ssh_bin} -F ${(q)SSH_CONFIG_FILE} -o LogLevel=ERROR -o StrictHostKeyChecking=${(q)TOKEN_STRICT_HOST_KEY_CHECKING} -o UserKnownHostsFile=${(q)TOKEN_USER_KNOWN_HOSTS_FILE}" if [[ -n "${TOKEN_SSH_USER:-}" ]]; then prefix+=" -l ${(q)TOKEN_SSH_USER}" @@ -429,7 +431,12 @@ proxy_jump_as_proxy_command() { } build_token_ssh_args() { - TOKEN_SSH_ARGS=(-F "${SSH_CONFIG_FILE}" -o LogLevel=ERROR) + TOKEN_SSH_ARGS=( + -F "${SSH_CONFIG_FILE}" + -o LogLevel=ERROR + -o "StrictHostKeyChecking=${TOKEN_STRICT_HOST_KEY_CHECKING}" + -o "UserKnownHostsFile=${TOKEN_USER_KNOWN_HOSTS_FILE}" + ) TOKEN_SSH_USER="$(resolve_token_ssh_user || true)" local proxy_command proxy_jump configured_proxy_command diff --git a/bin/codex-sso b/bin/codex-sso index c120a00..acd82e2 100755 --- a/bin/codex-sso +++ b/bin/codex-sso @@ -20,3 +20,4 @@ unset OPENAI_API_KEY unset CODEX_ACCESS_TOKEN "${CODEX_BIN}" --disable guardian_approval -a untrusted "$@" +# "${CODEX_BIN}" "$@" diff --git a/bin/copy-desktopasaservicedev-image-to-daaspreproduction.sh b/bin/copy-desktopasaservicedev-image-to-daaspreproduction.sh new file mode 100755 index 0000000..99107dd --- /dev/null +++ b/bin/copy-desktopasaservicedev-image-to-daaspreproduction.sh @@ -0,0 +1,465 @@ +#!/usr/bin/env bash +set +x +set -euo pipefail + +SCRIPT_NAME="$(basename "$0")" + +# Source tenancy/profile. Source images are produced in desktopasaservicedev. +SOURCE_PROFILE="${SOURCE_PROFILE:-MCP_GW_DEFAULT}" +SOURCE_AUTH="${SOURCE_AUTH:---auth security_token}" +read -r -a SOURCE_AUTH_ARGS <<< "$SOURCE_AUTH" +SOURCE_REGION="${SOURCE_REGION:-us-phoenix-1}" +SOURCE_EXPORT_BUCKET="${SOURCE_EXPORT_BUCKET:-desktop-images-OL-uploads}" +SOURCE_NAMESPACE="${SOURCE_NAMESPACE:-lrkymkoddq0d}" + +# Target tenancy/profile. +TARGET_PROFILE="${TARGET_PROFILE:-daaspreproduction}" +TARGET_REGION="${TARGET_REGION:-us-phoenix-1}" +TARGET_COMPARTMENT_OCID="${TARGET_COMPARTMENT_OCID:-ocid1.compartment.oc1..aaaaaaaarkpwynhpyooftr24a7s7gfjdhkerzidkqyrcmqj7ahijti6pilkq}" +TARGET_NAMESPACE="${TARGET_NAMESPACE:-id2t37chxkmi}" + +# Import/export behavior. +EXPORT_FORMAT="${EXPORT_FORMAT:-OCI}" +SOURCE_IMAGE_TYPE="${SOURCE_IMAGE_TYPE:-QCOW2}" +TARGET_DISPLAY_NAME_PREFIX="${TARGET_DISPLAY_NAME_PREFIX:-OSD }" +PAR_TTL_SECONDS="${PAR_TTL_SECONDS:-21600}" +EXPORT_POLL_INTERVAL_SECONDS="${EXPORT_POLL_INTERVAL_SECONDS:-60}" +EXPORT_TIMEOUT_SECONDS="${EXPORT_TIMEOUT_SECONDS:-21600}" +IMPORT_POLL_INTERVAL_SECONDS="${IMPORT_POLL_INTERVAL_SECONDS:-60}" +IMPORT_TIMEOUT_SECONDS="${IMPORT_TIMEOUT_SECONDS:-21600}" +COPY_DEFINED_TAGS="${COPY_DEFINED_TAGS:-1}" +DELETE_SOURCE_EXPORT_OBJECT="${DELETE_SOURCE_EXPORT_OBJECT:-0}" +PREFLIGHT_ONLY="${PREFLIGHT_ONLY:-0}" + +PAR_ID="" +PAR_CREATED=0 +TEMP_DIR="" +EXPORT_WORK_REQUEST_ID="" +EXPORT_OBJECT_NAME="" + +usage() { + cat >&2 <&2 +} + +fail() { + log "ERROR: $*" + exit 1 +} + +redact_stderr() { + sed -E \ + -e 's#https://objectstorage\.[^[:space:]"'"'"']+##g' \ + -e 's#/p/[-A-Za-z0-9_./?=%&:+]+##g' +} + +oci_source() { + if [[ -n "$SOURCE_AUTH" ]]; then + oci "$@" \ + --profile "$SOURCE_PROFILE" \ + "${SOURCE_AUTH_ARGS[@]}" \ + --region "$SOURCE_REGION" + else + oci "$@" \ + --profile "$SOURCE_PROFILE" \ + --region "$SOURCE_REGION" + fi +} + +oci_target() { + oci "$@" \ + --profile "$TARGET_PROFILE" \ + --region "$TARGET_REGION" +} + +require_command() { + command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1" +} + +cleanup() { + local status=$? + + if [[ "$PAR_CREATED" -eq 1 && -n "$PAR_ID" ]]; then + log "Deleting temporary source ObjectRead PAR" + if ! oci_source os preauth-request delete \ + --namespace-name "$SOURCE_NAMESPACE" \ + --bucket-name "$SOURCE_EXPORT_BUCKET" \ + --par-id "$PAR_ID" \ + --force >/dev/null 2> >(redact_stderr >&2); then + log "WARNING: failed to delete temporary PAR" + fi + fi + + if [[ -n "$TEMP_DIR" && -d "$TEMP_DIR" ]]; then + rm -rf "$TEMP_DIR" + fi + + exit "$status" +} +trap cleanup EXIT INT TERM + +json_string_or_empty() { + local file="$1" + local jq_filter="$2" + jq -r "${jq_filter} // empty" "$file" +} + +utc_after_seconds() { + local seconds="$1" + local epoch + epoch="$(($(date -u +%s) + seconds))" + + if date -u -r "$epoch" +%Y-%m-%dT%H:%M:%SZ >/dev/null 2>&1; then + date -u -r "$epoch" +%Y-%m-%dT%H:%M:%SZ + else + date -u -d "@$epoch" +%Y-%m-%dT%H:%M:%SZ + fi +} + +wait_for_export_object() { + local object_name="$1" + local start now elapsed + + start="$(date -u +%s)" + while true; do + if oci_source os object head \ + --namespace-name "$SOURCE_NAMESPACE" \ + --bucket-name "$SOURCE_EXPORT_BUCKET" \ + --name "$object_name" >/dev/null 2>/dev/null; then + log "Export object is available" + return 0 + fi + + now="$(date -u +%s)" + elapsed=$((now - start)) + if (( elapsed >= EXPORT_TIMEOUT_SECONDS )); then + fail "timed out waiting for exported object after ${EXPORT_TIMEOUT_SECONDS}s" + fi + + if [[ -n "$EXPORT_WORK_REQUEST_ID" ]]; then + log "Waiting for export object (${elapsed}s elapsed); export work request: $(export_work_request_summary "$EXPORT_WORK_REQUEST_ID")" + else + log "Waiting for export object (${elapsed}s elapsed)" + fi + sleep "$EXPORT_POLL_INTERVAL_SECONDS" + done +} + +export_work_request_summary() { + local work_request_id="$1" + local summary + + if ! summary="$( + oci_source work-requests work-request get \ + --work-request-id "$work_request_id" \ + --query 'data.{status:status,percentComplete:"percent-complete"}' \ + --raw-output 2>/dev/null + )"; then + printf 'unknown' + return 0 + fi + + jq -r '"\(.status) \(.percentComplete // 0)%"' <<<"$summary" +} + +find_latest_export_work_request() { + oci_source work-requests work-request list \ + --compartment-id "$SOURCE_COMPARTMENT_OCID" \ + --resource-id "$SOURCE_IMAGE_OCID" \ + --all \ + --query 'data' \ + --output json 2>/dev/null | + jq -r ' + map(select(."operation-type" == "ExportImage")) + | sort_by(."time-accepted") + | last + | .id // empty + ' +} + +preflight() { + local source_state bucket_name target_namespace target_compartment_state + + source_state="$(json_string_or_empty "$SOURCE_IMAGE_JSON" '.data."lifecycle-state"')" + if [[ "$source_state" != "AVAILABLE" ]]; then + fail "source image must be AVAILABLE, found: ${source_state:-unknown}" + fi + + log "Checking source export bucket ${SOURCE_NAMESPACE}/${SOURCE_EXPORT_BUCKET}" + bucket_name="$( + oci_source os bucket get \ + --namespace-name "$SOURCE_NAMESPACE" \ + --bucket-name "$SOURCE_EXPORT_BUCKET" \ + --query 'data.name' \ + --raw-output \ + 2> >(redact_stderr >&2) + )" + if [[ "$bucket_name" != "$SOURCE_EXPORT_BUCKET" ]]; then + fail "unexpected source bucket response: ${bucket_name:-empty}" + fi + + log "Checking target namespace" + target_namespace="$( + oci_target os ns get \ + --query data \ + --raw-output \ + 2> >(redact_stderr >&2) + )" + if [[ "$target_namespace" != "$TARGET_NAMESPACE" ]]; then + fail "target namespace mismatch: expected $TARGET_NAMESPACE, got ${target_namespace:-empty}" + fi + + log "Checking target compartment" + target_compartment_state="$( + oci_target iam compartment get \ + --compartment-id "$TARGET_COMPARTMENT_OCID" \ + --query 'data."lifecycle-state"' \ + --raw-output \ + 2> >(redact_stderr >&2) + )" + if [[ "$target_compartment_state" != "ACTIVE" ]]; then + fail "target compartment must be ACTIVE, found: ${target_compartment_state:-unknown}" + fi +} + +delete_source_export_object() { + if [[ "$DELETE_SOURCE_EXPORT_OBJECT" != "1" || -z "$EXPORT_OBJECT_NAME" ]]; then + return 0 + fi + + log "Deleting temporary source export object" + if ! oci_source os object delete \ + --namespace-name "$SOURCE_NAMESPACE" \ + --bucket-name "$SOURCE_EXPORT_BUCKET" \ + --object-name "$EXPORT_OBJECT_NAME" \ + --force >/dev/null \ + 2> >(redact_stderr >&2); then + log "WARNING: failed to delete temporary source export object" + fi +} + +build_import_json() { + local include_defined_tags="$1" + + jq -n \ + --arg compartment_id "$TARGET_COMPARTMENT_OCID" \ + --arg display_name "$TARGET_IMAGE_NAME" \ + --arg source_image_type "$SOURCE_IMAGE_TYPE" \ + --arg operating_system "$SOURCE_OPERATING_SYSTEM" \ + --arg operating_system_version "$SOURCE_OPERATING_SYSTEM_VERSION" \ + --arg launch_mode "$SOURCE_LAUNCH_MODE" \ + --slurpfile freeform_tags "$TEMP_DIR/freeform-tags.json" \ + --slurpfile defined_tags "$TEMP_DIR/defined-tags.json" \ + --arg include_defined_tags "$include_defined_tags" \ + ' + { + compartmentId: $compartment_id, + displayName: $display_name, + uri: env.OCI_IMAGE_IMPORT_URI, + sourceImageType: $source_image_type + } + + (if $operating_system == "" then {} else {operatingSystem: $operating_system} end) + + (if $operating_system_version == "" then {} else {operatingSystemVersion: $operating_system_version} end) + + (if $launch_mode == "" then {} else {launchMode: $launch_mode} end) + + (if ($freeform_tags[0] // {}) == {} then {} else {freeformTags: $freeform_tags[0]} end) + + ( + if $include_defined_tags != "1" or ($defined_tags[0] // {}) == {} then + {} + else + {definedTags: $defined_tags[0]} + end + ) + ' +} + +import_image() { + local include_defined_tags="$1" + + export OCI_IMAGE_IMPORT_URI + oci_target compute image import from-object-uri \ + --from-json "file://"<(build_import_json "$include_defined_tags") \ + --query 'data.id' \ + --raw-output \ + 2> >(redact_stderr >&2) +} + +poll_target_image() { + local target_image_ocid="$1" + local start now elapsed state + + start="$(date -u +%s)" + while true; do + state="$( + oci_target compute image get \ + --image-id "$target_image_ocid" \ + --query 'data."lifecycle-state"' \ + --raw-output \ + 2> >(redact_stderr >&2) + )" + + printf '%s %s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$state" + + case "$state" in + AVAILABLE) + return 0 + ;; + FAILED) + fail "target image reached FAILED: $target_image_ocid" + ;; + esac + + now="$(date -u +%s)" + elapsed=$((now - start)) + if (( elapsed >= IMPORT_TIMEOUT_SECONDS )); then + fail "timed out waiting for target image after ${IMPORT_TIMEOUT_SECONDS}s: $target_image_ocid" + fi + + sleep "$IMPORT_POLL_INTERVAL_SECONDS" + done +} + +if [[ "$#" -ne 1 ]]; then + usage + exit 2 +fi + +SOURCE_IMAGE_OCID="$1" + +require_command oci +require_command jq +require_command sed + +TEMP_DIR="$(mktemp -d)" + +if [[ -z "$SOURCE_NAMESPACE" ]]; then + log "Resolving source Object Storage namespace" + SOURCE_NAMESPACE="$( + oci_source os ns get \ + --query data \ + --raw-output \ + 2> >(redact_stderr >&2) + )" +fi + +log "Reading source image metadata" +SOURCE_IMAGE_JSON="$TEMP_DIR/source-image.json" +oci_source compute image get \ + --image-id "$SOURCE_IMAGE_OCID" \ + --output json \ + >"$SOURCE_IMAGE_JSON" \ + 2> >(redact_stderr >&2) + +SOURCE_DISPLAY_NAME="$(json_string_or_empty "$SOURCE_IMAGE_JSON" '.data."display-name"')" +SOURCE_OPERATING_SYSTEM="$(json_string_or_empty "$SOURCE_IMAGE_JSON" '.data."operating-system"')" +SOURCE_OPERATING_SYSTEM_VERSION="$(json_string_or_empty "$SOURCE_IMAGE_JSON" '.data."operating-system-version"')" +SOURCE_LAUNCH_MODE="$(json_string_or_empty "$SOURCE_IMAGE_JSON" '.data."launch-mode"')" +SOURCE_COMPARTMENT_OCID="$(json_string_or_empty "$SOURCE_IMAGE_JSON" '.data."compartment-id"')" + +preflight + +if [[ -n "$TARGET_DISPLAY_NAME_PREFIX" && "$SOURCE_DISPLAY_NAME" == "$TARGET_DISPLAY_NAME_PREFIX"* ]]; then + TARGET_IMAGE_NAME="$SOURCE_DISPLAY_NAME" +else + TARGET_IMAGE_NAME="${TARGET_DISPLAY_NAME_PREFIX}${SOURCE_DISPLAY_NAME}" +fi + +if [[ -z "$TARGET_IMAGE_NAME" ]]; then + TARGET_IMAGE_NAME="Copied custom image ${SOURCE_IMAGE_OCID}" +fi + +if [[ "$PREFLIGHT_ONLY" == "1" ]]; then + log "Preflight completed" + printf 'source_image=%s\n' "$SOURCE_IMAGE_OCID" + printf 'source_name=%s\n' "$SOURCE_DISPLAY_NAME" + printf 'target_name=%s\n' "$TARGET_IMAGE_NAME" + printf 'source_bucket=%s/%s\n' "$SOURCE_NAMESPACE" "$SOURCE_EXPORT_BUCKET" + printf 'target_compartment=%s\n' "$TARGET_COMPARTMENT_OCID" + exit 0 +fi + +jq '.data."freeform-tags" // {}' "$SOURCE_IMAGE_JSON" >"$TEMP_DIR/freeform-tags.json" +jq '.data."defined-tags" // {}' "$SOURCE_IMAGE_JSON" >"$TEMP_DIR/defined-tags.json" + +TIMESTAMP="$(date -u +%Y%m%dT%H%M%SZ)" +SAFE_SOURCE_IMAGE_OCID="${SOURCE_IMAGE_OCID//[^A-Za-z0-9._-]/_}" +EXPORT_OBJECT_NAME="image-copy-${SAFE_SOURCE_IMAGE_OCID}-${TIMESTAMP}.oci" +PAR_NAME="image-copy-${SAFE_SOURCE_IMAGE_OCID}-${TIMESTAMP}" +PAR_EXPIRES_AT="$(utc_after_seconds "$PAR_TTL_SECONDS")" + +log "Exporting source image to source Object Storage bucket ${SOURCE_EXPORT_BUCKET}" +oci_source compute image export to-object \ + --image-id "$SOURCE_IMAGE_OCID" \ + --export-format "$EXPORT_FORMAT" \ + --namespace "$SOURCE_NAMESPACE" \ + --bucket-name "$SOURCE_EXPORT_BUCKET" \ + --name "$EXPORT_OBJECT_NAME" \ + >/dev/null \ + 2> >(redact_stderr >&2) + +EXPORT_WORK_REQUEST_ID="$(find_latest_export_work_request)" +if [[ -n "$EXPORT_WORK_REQUEST_ID" ]]; then + log "Tracking export work request ${EXPORT_WORK_REQUEST_ID}" +else + log "WARNING: could not identify export work request; falling back to object polling only" +fi + +wait_for_export_object "$EXPORT_OBJECT_NAME" + +log "Creating short-lived source ObjectRead PAR" +PAR_JSON="$( + oci_source os preauth-request create \ + --namespace-name "$SOURCE_NAMESPACE" \ + --bucket-name "$SOURCE_EXPORT_BUCKET" \ + --name "$PAR_NAME" \ + --access-type ObjectRead \ + --object-name "$EXPORT_OBJECT_NAME" \ + --time-expires "$PAR_EXPIRES_AT" \ + --output json \ + 2> >(redact_stderr >&2) +)" +PAR_ID="$(jq -r '.data.id // empty' <<<"$PAR_JSON")" +PAR_ACCESS_URI="$(jq -r '.data."access-uri" // empty' <<<"$PAR_JSON")" +PAR_JSON="" + +if [[ -z "$PAR_ID" || -z "$PAR_ACCESS_URI" ]]; then + fail "PAR creation did not return both id and access URI" +fi +PAR_CREATED=1 + +OCI_IMAGE_IMPORT_URI="https://objectstorage.${SOURCE_REGION}.oraclecloud.com${PAR_ACCESS_URI}" +PAR_ACCESS_URI="" + +log "Importing image into daaspreproduction compartment" +if ! TARGET_IMAGE_OCID="$(import_image "$COPY_DEFINED_TAGS")"; then + if [[ "$COPY_DEFINED_TAGS" == "1" && "$(jq 'length' "$TEMP_DIR/defined-tags.json")" != "0" ]]; then + log "Import with copied defined tags failed; retrying without defined tags" + TARGET_IMAGE_OCID="$(import_image "0")" + else + fail "target image import failed" + fi +fi +unset OCI_IMAGE_IMPORT_URI + +if [[ -z "$TARGET_IMAGE_OCID" || "$TARGET_IMAGE_OCID" == "null" ]]; then + fail "target import did not return an image OCID" +fi + +log "Polling target image until AVAILABLE" +poll_target_image "$TARGET_IMAGE_OCID" + +delete_source_export_object + +printf '%s\n' "$TARGET_IMAGE_OCID"