Add --account N flag and full credential resolution to AWK, COBOL, Forth, Prolog
All four implementations now support: - --account N flag: bypasses env vars, loads credentials from accounts.csv row N - UNSANDBOX_ACCOUNT env var: selects default CSV row (fallback to row 0) - accounts.csv fallback: tries ~/.unsandbox/accounts.csv then ./accounts.csv - Correct priority: explicit flags > --account N > env vars > CSV row 0 AWK: Added load_accounts_csv() with native getline, GLOBAL_ACCOUNT_INDEX variable, pre-scan loop in END block for --account/-p/-k global flags. COBOL: Added GET-CREDENTIALS paragraph with shell-based CSV resolution, WS-ACCOUNT-INDEX variable, --account N parsing at start of MAIN-PROCEDURE, all HANDLE-* paragraphs now PERFORM GET-CREDENTIALS instead of inline credential fetching. Forth: Added account-index variable, load-accounts-csv-index word, sarg shifted-arg accessor, arg-shift variable, --account N detection in main. All handler N arg calls replaced with N sarg to support the shift. Prolog: Added load_accounts_csv/3 predicate with file I/O, nb_setval/nb_getval for account_index global, --account N pattern matching in main/1, get_public_key/1 and get_secret_key/1 now check account_index before env vars.
This commit is contained in:
parent
422985c6db
commit
7dd16bf796
4 changed files with 455 additions and 194 deletions
|
|
@ -64,6 +64,9 @@ BEGIN {
|
||||||
GREEN = "\033[32m"
|
GREEN = "\033[32m"
|
||||||
YELLOW = "\033[33m"
|
YELLOW = "\033[33m"
|
||||||
RESET = "\033[0m"
|
RESET = "\033[0m"
|
||||||
|
|
||||||
|
# Global credential state
|
||||||
|
GLOBAL_ACCOUNT_INDEX = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
@ -106,32 +109,84 @@ function health_check( cmd, result) {
|
||||||
return (result == "200")
|
return (result == "200")
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_api_keys( public_key, secret_key, cmd) {
|
function load_accounts_csv(index , home, path, line, fields, count, pk, sk) {
|
||||||
# Get public key
|
home = ENVIRON["HOME"]
|
||||||
cmd = "echo -n $UNSANDBOX_PUBLIC_KEY"
|
count = -1
|
||||||
cmd | getline public_key
|
pk = ""
|
||||||
close(cmd)
|
sk = ""
|
||||||
|
# Try ~/.unsandbox/accounts.csv first
|
||||||
# Get secret key
|
path = home "/.unsandbox/accounts.csv"
|
||||||
cmd = "echo -n $UNSANDBOX_SECRET_KEY"
|
while ((getline line < path) > 0) {
|
||||||
cmd | getline secret_key
|
if (line ~ /^[[:space:]]*$/ || line ~ /^[[:space:]]*#/) continue
|
||||||
close(cmd)
|
count++
|
||||||
|
if (count == index) {
|
||||||
# Fallback to old UNSANDBOX_API_KEY for backwards compat
|
split(line, fields, ",")
|
||||||
if (public_key == "") {
|
pk = fields[1]; sk = fields[2]
|
||||||
cmd = "echo -n $UNSANDBOX_API_KEY"
|
gsub(/^[[:space:]]+|[[:space:]]+$/, "", pk)
|
||||||
cmd | getline public_key
|
gsub(/^[[:space:]]+|[[:space:]]+$/, "", sk)
|
||||||
close(cmd)
|
close(path)
|
||||||
secret_key = ""
|
GLOBAL_PUBLIC_KEY = pk; GLOBAL_SECRET_KEY = sk
|
||||||
|
return 1
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
close(path)
|
||||||
|
# Try ./accounts.csv as fallback
|
||||||
|
count = -1; path = "accounts.csv"
|
||||||
|
while ((getline line < path) > 0) {
|
||||||
|
if (line ~ /^[[:space:]]*$/ || line ~ /^[[:space:]]*#/) continue
|
||||||
|
count++
|
||||||
|
if (count == index) {
|
||||||
|
split(line, fields, ",")
|
||||||
|
pk = fields[1]; sk = fields[2]
|
||||||
|
gsub(/^[[:space:]]+|[[:space:]]+$/, "", pk)
|
||||||
|
gsub(/^[[:space:]]+|[[:space:]]+$/, "", sk)
|
||||||
|
close(path)
|
||||||
|
GLOBAL_PUBLIC_KEY = pk; GLOBAL_SECRET_KEY = sk
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(path)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
if (public_key == "") {
|
function get_api_keys( public_key, secret_key, cmd, default_index) {
|
||||||
print RED "Error: UNSANDBOX_PUBLIC_KEY or UNSANDBOX_API_KEY not set" RESET > "/dev/stderr"
|
# Priority 1: already set via -p/-k flags
|
||||||
|
if (GLOBAL_PUBLIC_KEY != "" && GLOBAL_SECRET_KEY != "") { return }
|
||||||
|
|
||||||
|
# Priority 2: --account N bypasses env vars
|
||||||
|
if (GLOBAL_ACCOUNT_INDEX >= 0) {
|
||||||
|
if (load_accounts_csv(GLOBAL_ACCOUNT_INDEX)) {
|
||||||
|
if (GLOBAL_PUBLIC_KEY != "") return
|
||||||
|
}
|
||||||
|
print RED "Error: Account index " GLOBAL_ACCOUNT_INDEX " not found in accounts.csv" RESET > "/dev/stderr"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
GLOBAL_PUBLIC_KEY = public_key
|
# Priority 3: env vars UNSANDBOX_PUBLIC_KEY / UNSANDBOX_SECRET_KEY
|
||||||
GLOBAL_SECRET_KEY = secret_key
|
cmd = "echo -n $UNSANDBOX_PUBLIC_KEY"; cmd | getline public_key; close(cmd)
|
||||||
|
cmd = "echo -n $UNSANDBOX_SECRET_KEY"; cmd | getline secret_key; close(cmd)
|
||||||
|
if (public_key != "" && secret_key != "") {
|
||||||
|
GLOBAL_PUBLIC_KEY = public_key; GLOBAL_SECRET_KEY = secret_key; return
|
||||||
|
}
|
||||||
|
|
||||||
|
# Fallback to legacy UNSANDBOX_API_KEY for backwards compat
|
||||||
|
if (public_key == "") {
|
||||||
|
cmd = "echo -n $UNSANDBOX_API_KEY"; cmd | getline public_key; close(cmd)
|
||||||
|
secret_key = ""
|
||||||
|
}
|
||||||
|
if (public_key != "") {
|
||||||
|
GLOBAL_PUBLIC_KEY = public_key; GLOBAL_SECRET_KEY = secret_key; return
|
||||||
|
}
|
||||||
|
|
||||||
|
# Priority 4/5: accounts.csv with UNSANDBOX_ACCOUNT env var or row 0
|
||||||
|
cmd = "echo -n $UNSANDBOX_ACCOUNT"; cmd | getline default_index; close(cmd)
|
||||||
|
if (default_index == "") default_index = 0
|
||||||
|
if (load_accounts_csv(default_index + 0)) {
|
||||||
|
if (GLOBAL_PUBLIC_KEY != "") return
|
||||||
|
}
|
||||||
|
|
||||||
|
print RED "Error: UNSANDBOX_PUBLIC_KEY or UNSANDBOX_API_KEY not set" RESET > "/dev/stderr"
|
||||||
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_extension(filename) {
|
function get_extension(filename) {
|
||||||
|
|
@ -2359,6 +2414,20 @@ END {
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Pre-scan ARGV for global flags: --account N, -p KEY, -k KEY
|
||||||
|
for (_gi = 1; _gi < ARGC; _gi++) {
|
||||||
|
if (ARGV[_gi] == "--account" && _gi + 1 < ARGC) {
|
||||||
|
GLOBAL_ACCOUNT_INDEX = ARGV[_gi + 1] + 0
|
||||||
|
_gi++
|
||||||
|
} else if (ARGV[_gi] == "-p" && _gi + 1 < ARGC) {
|
||||||
|
GLOBAL_PUBLIC_KEY = ARGV[_gi + 1]
|
||||||
|
_gi++
|
||||||
|
} else if (ARGV[_gi] == "-k" && _gi + 1 < ARGC) {
|
||||||
|
GLOBAL_SECRET_KEY = ARGV[_gi + 1]
|
||||||
|
_gi++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ARGV[1] == "session") {
|
if (ARGV[1] == "session") {
|
||||||
if (ARGC >= 3 && ARGV[2] == "--list") {
|
if (ARGC >= 3 && ARGV[2] == "--list") {
|
||||||
session_list()
|
session_list()
|
||||||
|
|
|
||||||
|
|
@ -45,15 +45,21 @@
|
||||||
SELECT SOURCE-FILE ASSIGN TO WS-FILENAME
|
SELECT SOURCE-FILE ASSIGN TO WS-FILENAME
|
||||||
ORGANIZATION IS LINE SEQUENTIAL
|
ORGANIZATION IS LINE SEQUENTIAL
|
||||||
FILE STATUS IS WS-FILE-STATUS.
|
FILE STATUS IS WS-FILE-STATUS.
|
||||||
|
SELECT CRED-FILE ASSIGN TO "/tmp/unsb_creds.txt"
|
||||||
|
ORGANIZATION IS LINE SEQUENTIAL
|
||||||
|
FILE STATUS IS WS-CRED-STATUS.
|
||||||
|
|
||||||
DATA DIVISION.
|
DATA DIVISION.
|
||||||
FILE SECTION.
|
FILE SECTION.
|
||||||
FD SOURCE-FILE.
|
FD SOURCE-FILE.
|
||||||
01 SOURCE-LINE PIC X(1024).
|
01 SOURCE-LINE PIC X(1024).
|
||||||
|
FD CRED-FILE.
|
||||||
|
01 CRED-LINE PIC X(512).
|
||||||
|
|
||||||
WORKING-STORAGE SECTION.
|
WORKING-STORAGE SECTION.
|
||||||
01 WS-FILENAME PIC X(256).
|
01 WS-FILENAME PIC X(256).
|
||||||
01 WS-FILE-STATUS PIC XX.
|
01 WS-FILE-STATUS PIC XX.
|
||||||
|
01 WS-CRED-STATUS PIC XX.
|
||||||
01 WS-API-KEY PIC X(256).
|
01 WS-API-KEY PIC X(256).
|
||||||
01 WS-PUBLIC-KEY PIC X(256).
|
01 WS-PUBLIC-KEY PIC X(256).
|
||||||
01 WS-SECRET-KEY PIC X(256).
|
01 WS-SECRET-KEY PIC X(256).
|
||||||
|
|
@ -97,12 +103,23 @@
|
||||||
01 WS-UOD-ENABLED PIC X(8).
|
01 WS-UOD-ENABLED PIC X(8).
|
||||||
01 WS-TYPE PIC X(32).
|
01 WS-TYPE PIC X(32).
|
||||||
01 WS-SHELL PIC X(32).
|
01 WS-SHELL PIC X(32).
|
||||||
|
01 WS-ACCOUNT-INDEX PIC S9(4) VALUE -1.
|
||||||
|
01 WS-ACCOUNT-STR PIC X(16).
|
||||||
|
01 WS-ACCT-POS PIC 9(4) VALUE 0.
|
||||||
|
01 WS-ERROR-MSG PIC X(256).
|
||||||
|
|
||||||
PROCEDURE DIVISION.
|
PROCEDURE DIVISION.
|
||||||
MAIN-PROCEDURE.
|
MAIN-PROCEDURE.
|
||||||
* Get command line argument (first argument)
|
* Get first command line argument
|
||||||
ACCEPT WS-ARG1 FROM COMMAND-LINE.
|
ACCEPT WS-ARG1 FROM COMMAND-LINE.
|
||||||
|
|
||||||
|
* Pre-scan: handle --account N global flag before subcommand
|
||||||
|
IF WS-ARG1 = "--account"
|
||||||
|
ACCEPT WS-ACCOUNT-STR FROM ARGUMENT-VALUE
|
||||||
|
MOVE FUNCTION NUMVAL(WS-ACCOUNT-STR) TO WS-ACCOUNT-INDEX
|
||||||
|
ACCEPT WS-ARG1 FROM ARGUMENT-VALUE
|
||||||
|
END-IF.
|
||||||
|
|
||||||
IF WS-ARG1 = SPACES
|
IF WS-ARG1 = SPACES
|
||||||
DISPLAY "Usage: un.cob <source_file>" UPON SYSERR
|
DISPLAY "Usage: un.cob <source_file>" UPON SYSERR
|
||||||
DISPLAY " un.cob session [options]" UPON SYSERR
|
DISPLAY " un.cob session [options]" UPON SYSERR
|
||||||
|
|
@ -147,7 +164,94 @@
|
||||||
PERFORM HANDLE-EXECUTE.
|
PERFORM HANDLE-EXECUTE.
|
||||||
STOP RUN.
|
STOP RUN.
|
||||||
|
|
||||||
|
GET-CREDENTIALS.
|
||||||
|
* If already set, return immediately
|
||||||
|
IF WS-PUBLIC-KEY NOT = SPACES AND WS-SECRET-KEY NOT = SPACES
|
||||||
|
EXIT PARAGRAPH
|
||||||
|
END-IF.
|
||||||
|
|
||||||
|
* Build shell script to resolve credentials with full priority
|
||||||
|
IF WS-ACCOUNT-INDEX >= 0
|
||||||
|
MOVE WS-ACCOUNT-INDEX TO WS-ACCOUNT-STR
|
||||||
|
STRING "IDX=" FUNCTION TRIM(WS-ACCOUNT-STR) "; "
|
||||||
|
"PK=''; SK=''; CNT=-1; "
|
||||||
|
"for CSV in \"$HOME/.unsandbox/accounts.csv\" "
|
||||||
|
"\"./accounts.csv\"; do "
|
||||||
|
"[ -f \"$CSV\" ] || continue; "
|
||||||
|
"while IFS= read -r line || [ -n \"$line\" ]; do "
|
||||||
|
"case \"$line\" in \"#\"*|\"\"|\" \"*) continue ;; esac; "
|
||||||
|
"CNT=$((CNT+1)); "
|
||||||
|
"if [ \"$CNT\" -eq \"$IDX\" ]; then "
|
||||||
|
"PK=$(echo \"$line\" | cut -d',' -f1 | tr -d ' '); "
|
||||||
|
"SK=$(echo \"$line\" | cut -d',' -f2 | tr -d ' '); "
|
||||||
|
"break 2; fi; "
|
||||||
|
"done < \"$CSV\"; done; "
|
||||||
|
"if [ -z \"$PK\" ]; then "
|
||||||
|
"echo -e '\\x1b[31mError: Account index "
|
||||||
|
FUNCTION TRIM(WS-ACCOUNT-STR)
|
||||||
|
" not found in accounts.csv\\x1b[0m' >&2; exit 1; fi; "
|
||||||
|
"printf '%s\\n%s\\n' \"$PK\" \"$SK\" "
|
||||||
|
"> /tmp/unsb_creds.txt"
|
||||||
|
DELIMITED BY SIZE INTO WS-CURL-CMD
|
||||||
|
END-STRING
|
||||||
|
ELSE
|
||||||
|
STRING "PK=\"$UNSANDBOX_PUBLIC_KEY\"; "
|
||||||
|
"SK=\"$UNSANDBOX_SECRET_KEY\"; "
|
||||||
|
"if [ -z \"$PK\" ]; then PK=\"$UNSANDBOX_API_KEY\"; SK=''; fi; "
|
||||||
|
"if [ -z \"$PK\" ]; then "
|
||||||
|
"IDX=\"${UNSANDBOX_ACCOUNT:-0}\"; "
|
||||||
|
"CNT=-1; "
|
||||||
|
"for CSV in \"$HOME/.unsandbox/accounts.csv\" "
|
||||||
|
"\"./accounts.csv\"; do "
|
||||||
|
"[ -f \"$CSV\" ] || continue; "
|
||||||
|
"while IFS= read -r line || [ -n \"$line\" ]; do "
|
||||||
|
"case \"$line\" in \"#\"*|\"\"|\" \"*) continue ;; esac; "
|
||||||
|
"CNT=$((CNT+1)); "
|
||||||
|
"if [ \"$CNT\" -eq \"$IDX\" ]; then "
|
||||||
|
"PK=$(echo \"$line\" | cut -d',' -f1 | tr -d ' '); "
|
||||||
|
"SK=$(echo \"$line\" | cut -d',' -f2 | tr -d ' '); "
|
||||||
|
"break 2; fi; "
|
||||||
|
"done < \"$CSV\"; done; fi; "
|
||||||
|
"if [ -z \"$PK\" ]; then "
|
||||||
|
"echo -e '\\x1b[31mError: No credentials found\\x1b[0m' "
|
||||||
|
">&2; exit 1; fi; "
|
||||||
|
"printf '%s\\n%s\\n' \"$PK\" \"$SK\" "
|
||||||
|
"> /tmp/unsb_creds.txt"
|
||||||
|
DELIMITED BY SIZE INTO WS-CURL-CMD
|
||||||
|
END-STRING
|
||||||
|
END-IF.
|
||||||
|
|
||||||
|
CALL "SYSTEM" USING WS-CURL-CMD
|
||||||
|
RETURNING WS-EXIT-CODE.
|
||||||
|
IF WS-EXIT-CODE NOT = 0
|
||||||
|
MOVE WS-EXIT-CODE TO RETURN-CODE
|
||||||
|
STOP RUN
|
||||||
|
END-IF.
|
||||||
|
|
||||||
|
* Read resolved credentials from temp file
|
||||||
|
MOVE SPACES TO WS-PUBLIC-KEY.
|
||||||
|
MOVE SPACES TO WS-SECRET-KEY.
|
||||||
|
OPEN INPUT CRED-FILE.
|
||||||
|
IF WS-CRED-STATUS = "00"
|
||||||
|
READ CRED-FILE INTO WS-PUBLIC-KEY
|
||||||
|
READ CRED-FILE INTO WS-SECRET-KEY
|
||||||
|
CLOSE CRED-FILE
|
||||||
|
END-IF.
|
||||||
|
|
||||||
|
IF WS-PUBLIC-KEY = SPACES
|
||||||
|
DISPLAY "Error: Could not resolve credentials"
|
||||||
|
UPON SYSERR
|
||||||
|
MOVE 1 TO RETURN-CODE
|
||||||
|
STOP RUN
|
||||||
|
END-IF.
|
||||||
|
|
||||||
HANDLE-EXECUTE.
|
HANDLE-EXECUTE.
|
||||||
|
* Get credentials
|
||||||
|
PERFORM GET-CREDENTIALS.
|
||||||
|
IF WS-API-KEY = SPACES
|
||||||
|
MOVE WS-PUBLIC-KEY TO WS-API-KEY
|
||||||
|
END-IF.
|
||||||
|
|
||||||
* Check if file exists
|
* Check if file exists
|
||||||
OPEN INPUT SOURCE-FILE.
|
OPEN INPUT SOURCE-FILE.
|
||||||
IF WS-FILE-STATUS NOT = "00"
|
IF WS-FILE-STATUS NOT = "00"
|
||||||
|
|
@ -168,25 +272,14 @@
|
||||||
STOP RUN
|
STOP RUN
|
||||||
END-IF.
|
END-IF.
|
||||||
|
|
||||||
* Get API key from environment
|
|
||||||
ACCEPT WS-API-KEY FROM ENVIRONMENT "UNSANDBOX_API_KEY".
|
|
||||||
|
|
||||||
IF WS-API-KEY = SPACES
|
|
||||||
DISPLAY "Error: UNSANDBOX_API_KEY not set" UPON SYSERR
|
|
||||||
MOVE 1 TO RETURN-CODE
|
|
||||||
STOP RUN
|
|
||||||
END-IF.
|
|
||||||
|
|
||||||
* Use curl to make request
|
* Use curl to make request
|
||||||
PERFORM MAKE-EXECUTE-REQUEST.
|
PERFORM MAKE-EXECUTE-REQUEST.
|
||||||
|
|
||||||
HANDLE-SESSION.
|
HANDLE-SESSION.
|
||||||
* Get API key
|
* Get credentials
|
||||||
ACCEPT WS-API-KEY FROM ENVIRONMENT "UNSANDBOX_API_KEY".
|
PERFORM GET-CREDENTIALS.
|
||||||
IF WS-API-KEY = SPACES
|
IF WS-API-KEY = SPACES
|
||||||
DISPLAY "Error: UNSANDBOX_API_KEY not set" UPON SYSERR
|
MOVE WS-PUBLIC-KEY TO WS-API-KEY
|
||||||
MOVE 1 TO RETURN-CODE
|
|
||||||
STOP RUN
|
|
||||||
END-IF.
|
END-IF.
|
||||||
|
|
||||||
* Initialize session parameters
|
* Initialize session parameters
|
||||||
|
|
@ -209,27 +302,8 @@
|
||||||
END-IF.
|
END-IF.
|
||||||
|
|
||||||
HANDLE-SERVICE.
|
HANDLE-SERVICE.
|
||||||
* Get API keys (try new format first, fall back to old)
|
* Get credentials
|
||||||
ACCEPT WS-PUBLIC-KEY FROM ENVIRONMENT "UNSANDBOX_PUBLIC_KEY".
|
PERFORM GET-CREDENTIALS.
|
||||||
IF WS-PUBLIC-KEY NOT = SPACES
|
|
||||||
ACCEPT WS-SECRET-KEY FROM ENVIRONMENT "UNSANDBOX_SECRET_KEY"
|
|
||||||
IF WS-SECRET-KEY = SPACES
|
|
||||||
DISPLAY "Error: UNSANDBOX_SECRET_KEY not set"
|
|
||||||
UPON SYSERR
|
|
||||||
MOVE 1 TO RETURN-CODE
|
|
||||||
STOP RUN
|
|
||||||
END-IF
|
|
||||||
ELSE
|
|
||||||
ACCEPT WS-API-KEY FROM ENVIRONMENT "UNSANDBOX_API_KEY"
|
|
||||||
IF WS-API-KEY = SPACES
|
|
||||||
DISPLAY "Error: UNSANDBOX_PUBLIC_KEY/SECRET_KEY or "
|
|
||||||
"UNSANDBOX_API_KEY not set" UPON SYSERR
|
|
||||||
MOVE 1 TO RETURN-CODE
|
|
||||||
STOP RUN
|
|
||||||
END-IF
|
|
||||||
MOVE WS-API-KEY TO WS-PUBLIC-KEY
|
|
||||||
MOVE WS-API-KEY TO WS-SECRET-KEY
|
|
||||||
END-IF.
|
|
||||||
|
|
||||||
* Initialize service parameters
|
* Initialize service parameters
|
||||||
MOVE SPACES TO WS-NAME.
|
MOVE SPACES TO WS-NAME.
|
||||||
|
|
@ -332,26 +406,7 @@
|
||||||
END-IF.
|
END-IF.
|
||||||
|
|
||||||
MAKE-EXECUTE-REQUEST.
|
MAKE-EXECUTE-REQUEST.
|
||||||
* Get public/secret keys with fallback
|
* Credentials already resolved by caller (GET-CREDENTIALS)
|
||||||
ACCEPT WS-PUBLIC-KEY FROM ENVIRONMENT "UNSANDBOX_PUBLIC_KEY".
|
|
||||||
IF WS-PUBLIC-KEY NOT = SPACES
|
|
||||||
ACCEPT WS-SECRET-KEY FROM ENVIRONMENT "UNSANDBOX_SECRET_KEY"
|
|
||||||
IF WS-SECRET-KEY = SPACES
|
|
||||||
DISPLAY "Error: UNSANDBOX_SECRET_KEY not set"
|
|
||||||
UPON SYSERR
|
|
||||||
MOVE 1 TO RETURN-CODE
|
|
||||||
STOP RUN
|
|
||||||
END-IF
|
|
||||||
ELSE
|
|
||||||
ACCEPT WS-PUBLIC-KEY FROM ENVIRONMENT "UNSANDBOX_API_KEY"
|
|
||||||
IF WS-PUBLIC-KEY = SPACES
|
|
||||||
DISPLAY "Error: UNSANDBOX_PUBLIC_KEY/SECRET_KEY or "
|
|
||||||
"UNSANDBOX_API_KEY not set" UPON SYSERR
|
|
||||||
MOVE 1 TO RETURN-CODE
|
|
||||||
STOP RUN
|
|
||||||
END-IF
|
|
||||||
MOVE WS-PUBLIC-KEY TO WS-SECRET-KEY
|
|
||||||
END-IF.
|
|
||||||
|
|
||||||
* Build curl command using shell with HMAC signature
|
* Build curl command using shell with HMAC signature
|
||||||
STRING "TS=$(date +%s); "
|
STRING "TS=$(date +%s); "
|
||||||
|
|
@ -943,12 +998,10 @@
|
||||||
CALL "SYSTEM" USING WS-CURL-CMD.
|
CALL "SYSTEM" USING WS-CURL-CMD.
|
||||||
|
|
||||||
HANDLE-KEY.
|
HANDLE-KEY.
|
||||||
* Get API key
|
* Get credentials
|
||||||
ACCEPT WS-API-KEY FROM ENVIRONMENT "UNSANDBOX_API_KEY".
|
PERFORM GET-CREDENTIALS.
|
||||||
IF WS-API-KEY = SPACES
|
IF WS-API-KEY = SPACES
|
||||||
DISPLAY "Error: UNSANDBOX_API_KEY not set" UPON SYSERR
|
MOVE WS-PUBLIC-KEY TO WS-API-KEY
|
||||||
MOVE 1 TO RETURN-CODE
|
|
||||||
STOP RUN
|
|
||||||
END-IF.
|
END-IF.
|
||||||
|
|
||||||
* Parse key arguments
|
* Parse key arguments
|
||||||
|
|
@ -1124,27 +1177,8 @@
|
||||||
CALL "SYSTEM" USING WS-CURL-CMD.
|
CALL "SYSTEM" USING WS-CURL-CMD.
|
||||||
|
|
||||||
HANDLE-LANGUAGES.
|
HANDLE-LANGUAGES.
|
||||||
* Get API keys
|
* Get credentials
|
||||||
ACCEPT WS-PUBLIC-KEY FROM ENVIRONMENT "UNSANDBOX_PUBLIC_KEY".
|
PERFORM GET-CREDENTIALS.
|
||||||
IF WS-PUBLIC-KEY NOT = SPACES
|
|
||||||
ACCEPT WS-SECRET-KEY FROM ENVIRONMENT "UNSANDBOX_SECRET_KEY"
|
|
||||||
IF WS-SECRET-KEY = SPACES
|
|
||||||
DISPLAY "Error: UNSANDBOX_SECRET_KEY not set"
|
|
||||||
UPON SYSERR
|
|
||||||
MOVE 1 TO RETURN-CODE
|
|
||||||
STOP RUN
|
|
||||||
END-IF
|
|
||||||
ELSE
|
|
||||||
ACCEPT WS-API-KEY FROM ENVIRONMENT "UNSANDBOX_API_KEY"
|
|
||||||
IF WS-API-KEY = SPACES
|
|
||||||
DISPLAY "Error: UNSANDBOX_PUBLIC_KEY/SECRET_KEY or "
|
|
||||||
"UNSANDBOX_API_KEY not set" UPON SYSERR
|
|
||||||
MOVE 1 TO RETURN-CODE
|
|
||||||
STOP RUN
|
|
||||||
END-IF
|
|
||||||
MOVE WS-API-KEY TO WS-PUBLIC-KEY
|
|
||||||
MOVE WS-API-KEY TO WS-SECRET-KEY
|
|
||||||
END-IF.
|
|
||||||
|
|
||||||
* Parse --json flag
|
* Parse --json flag
|
||||||
MOVE SPACES TO WS-JSON-OUTPUT.
|
MOVE SPACES TO WS-JSON-OUTPUT.
|
||||||
|
|
@ -1219,27 +1253,8 @@
|
||||||
CALL "SYSTEM" USING WS-CURL-CMD.
|
CALL "SYSTEM" USING WS-CURL-CMD.
|
||||||
|
|
||||||
HANDLE-IMAGE.
|
HANDLE-IMAGE.
|
||||||
* Get API keys (try new format first, fall back to old)
|
* Get credentials
|
||||||
ACCEPT WS-PUBLIC-KEY FROM ENVIRONMENT "UNSANDBOX_PUBLIC_KEY".
|
PERFORM GET-CREDENTIALS.
|
||||||
IF WS-PUBLIC-KEY NOT = SPACES
|
|
||||||
ACCEPT WS-SECRET-KEY FROM ENVIRONMENT "UNSANDBOX_SECRET_KEY"
|
|
||||||
IF WS-SECRET-KEY = SPACES
|
|
||||||
DISPLAY "Error: UNSANDBOX_SECRET_KEY not set"
|
|
||||||
UPON SYSERR
|
|
||||||
MOVE 1 TO RETURN-CODE
|
|
||||||
STOP RUN
|
|
||||||
END-IF
|
|
||||||
ELSE
|
|
||||||
ACCEPT WS-API-KEY FROM ENVIRONMENT "UNSANDBOX_API_KEY"
|
|
||||||
IF WS-API-KEY = SPACES
|
|
||||||
DISPLAY "Error: UNSANDBOX_PUBLIC_KEY/SECRET_KEY or "
|
|
||||||
"UNSANDBOX_API_KEY not set" UPON SYSERR
|
|
||||||
MOVE 1 TO RETURN-CODE
|
|
||||||
STOP RUN
|
|
||||||
END-IF
|
|
||||||
MOVE WS-API-KEY TO WS-PUBLIC-KEY
|
|
||||||
MOVE WS-API-KEY TO WS-SECRET-KEY
|
|
||||||
END-IF.
|
|
||||||
|
|
||||||
* Initialize image parameters
|
* Initialize image parameters
|
||||||
MOVE SPACES TO WS-ID.
|
MOVE SPACES TO WS-ID.
|
||||||
|
|
@ -1676,15 +1691,7 @@
|
||||||
|
|
||||||
HANDLE-SNAPSHOT.
|
HANDLE-SNAPSHOT.
|
||||||
* Get credentials
|
* Get credentials
|
||||||
ACCEPT WS-PUBLIC-KEY FROM ENVIRONMENT
|
PERFORM GET-CREDENTIALS.
|
||||||
"UNSANDBOX_PUBLIC_KEY".
|
|
||||||
ACCEPT WS-SECRET-KEY FROM ENVIRONMENT
|
|
||||||
"UNSANDBOX_SECRET_KEY".
|
|
||||||
IF WS-PUBLIC-KEY = SPACES OR WS-SECRET-KEY = SPACES
|
|
||||||
DISPLAY "Error: API keys not set" UPON SYSERR
|
|
||||||
MOVE 1 TO RETURN-CODE
|
|
||||||
STOP RUN
|
|
||||||
END-IF.
|
|
||||||
|
|
||||||
* Get second argument (operation or --list)
|
* Get second argument (operation or --list)
|
||||||
ACCEPT WS-ARG2 FROM ARGUMENT-VALUE.
|
ACCEPT WS-ARG2 FROM ARGUMENT-VALUE.
|
||||||
|
|
|
||||||
|
|
@ -97,8 +97,84 @@
|
||||||
find-ext ext-lang
|
find-ext ext-lang
|
||||||
;
|
;
|
||||||
|
|
||||||
|
\ Account index for --account N flag (-1 = not set)
|
||||||
|
variable account-index
|
||||||
|
-1 account-index !
|
||||||
|
|
||||||
|
\ Argument shift: 0 normally, 2 when --account N is prepended
|
||||||
|
variable arg-shift
|
||||||
|
0 arg-shift !
|
||||||
|
|
||||||
|
\ Shifted arg accessor - applies arg-shift to all handler arg accesses
|
||||||
|
: sarg ( n -- addr len )
|
||||||
|
arg-shift @ + arg
|
||||||
|
;
|
||||||
|
|
||||||
|
\ Buffer for credentials loaded from CSV
|
||||||
|
256 constant MAX-KEY-LEN
|
||||||
|
create csv-pk-buf MAX-KEY-LEN allot
|
||||||
|
variable csv-pk-len
|
||||||
|
create csv-sk-buf MAX-KEY-LEN allot
|
||||||
|
variable csv-sk-len
|
||||||
|
|
||||||
|
\ Load credentials from accounts.csv at given index (n)
|
||||||
|
\ Writes PK/SK to /tmp/unsb_creds.txt; returns true if PK found
|
||||||
|
: load-accounts-csv-index ( n -- flag )
|
||||||
|
dup 0< if drop 0 exit then
|
||||||
|
\ Write a shell script with the index embedded
|
||||||
|
s" /tmp/unsb_cred_resolve.sh" w/o create-file throw >r
|
||||||
|
s" #!/bin/bash" r@ write-line throw
|
||||||
|
s" IDX=" r@ write-file throw
|
||||||
|
dup 0 <# #s #> r@ write-file throw
|
||||||
|
s" " r@ write-line throw
|
||||||
|
s" CNT=-1; PK=''; SK=''" r@ write-line throw
|
||||||
|
s" for CSV in \"$HOME/.unsandbox/accounts.csv\" \"./accounts.csv\"; do" r@ write-line throw
|
||||||
|
s" [ -f \"$CSV\" ] || continue" r@ write-line throw
|
||||||
|
s" while IFS= read -r line || [ -n \"$line\" ]; do" r@ write-line throw
|
||||||
|
s" case \"$line\" in '#'*|'') continue ;; esac" r@ write-line throw
|
||||||
|
s" CNT=$((CNT+1))" r@ write-line throw
|
||||||
|
s" if [ \"$CNT\" -eq \"$IDX\" ]; then" r@ write-line throw
|
||||||
|
s" PK=$(echo \"$line\" | cut -d',' -f1 | tr -d ' ')" r@ write-line throw
|
||||||
|
s" SK=$(echo \"$line\" | cut -d',' -f2 | tr -d ' ')" r@ write-line throw
|
||||||
|
s" break 2" r@ write-line throw
|
||||||
|
s" fi" r@ write-line throw
|
||||||
|
s" done < \"$CSV\"" r@ write-line throw
|
||||||
|
s" done" r@ write-line throw
|
||||||
|
s" printf '%s\\n%s\\n' \"$PK\" \"$SK\" > /tmp/unsb_creds.txt" r@ write-line throw
|
||||||
|
s" [ -n \"$PK\" ]" r@ write-line throw
|
||||||
|
r> close-file throw
|
||||||
|
drop \ drop index
|
||||||
|
s" bash /tmp/unsb_cred_resolve.sh" system
|
||||||
|
0= if
|
||||||
|
\ Script exited 0: PK was found; read results
|
||||||
|
s" /tmp/unsb_creds.txt" r/o open-file
|
||||||
|
0= if
|
||||||
|
>r
|
||||||
|
csv-pk-buf MAX-KEY-LEN r@ read-line throw
|
||||||
|
drop csv-pk-len !
|
||||||
|
csv-sk-buf MAX-KEY-LEN r@ read-line throw
|
||||||
|
drop csv-sk-len !
|
||||||
|
r> close-file throw
|
||||||
|
-1
|
||||||
|
else
|
||||||
|
drop 0
|
||||||
|
then
|
||||||
|
else
|
||||||
|
0
|
||||||
|
then
|
||||||
|
;
|
||||||
|
|
||||||
\ Get API keys from environment (HMAC or legacy)
|
\ Get API keys from environment (HMAC or legacy)
|
||||||
: get-public-key ( -- addr len )
|
: get-public-key ( -- addr len )
|
||||||
|
account-index @ dup 0>= if
|
||||||
|
load-accounts-csv-index if
|
||||||
|
csv-pk-buf csv-pk-len @ exit
|
||||||
|
then
|
||||||
|
s" Error: Account index not found in accounts.csv" type cr
|
||||||
|
1 (bye)
|
||||||
|
else
|
||||||
|
drop
|
||||||
|
then
|
||||||
s" UNSANDBOX_PUBLIC_KEY" getenv
|
s" UNSANDBOX_PUBLIC_KEY" getenv
|
||||||
dup 0= if
|
dup 0= if
|
||||||
2drop s" UNSANDBOX_API_KEY" getenv
|
2drop s" UNSANDBOX_API_KEY" getenv
|
||||||
|
|
@ -110,6 +186,20 @@
|
||||||
;
|
;
|
||||||
|
|
||||||
: get-secret-key ( -- addr len )
|
: get-secret-key ( -- addr len )
|
||||||
|
account-index @ dup 0>= if
|
||||||
|
\ CSV already loaded if pk-buf is non-empty
|
||||||
|
csv-pk-len @ 0> if
|
||||||
|
drop csv-sk-buf csv-sk-len @ exit
|
||||||
|
then
|
||||||
|
\ Load it now
|
||||||
|
load-accounts-csv-index if
|
||||||
|
csv-sk-buf csv-sk-len @ exit
|
||||||
|
then
|
||||||
|
\ Index not found - error was printed by get-public-key; return empty
|
||||||
|
s" " exit
|
||||||
|
else
|
||||||
|
drop
|
||||||
|
then
|
||||||
s" UNSANDBOX_SECRET_KEY" getenv
|
s" UNSANDBOX_SECRET_KEY" getenv
|
||||||
dup 0= if
|
dup 0= if
|
||||||
2drop s" UNSANDBOX_API_KEY" getenv
|
2drop s" UNSANDBOX_API_KEY" getenv
|
||||||
|
|
@ -716,7 +806,7 @@
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
2 arg 2dup s" --extend" compare 0= if
|
2 sarg 2dup s" --extend" compare 0= if
|
||||||
2drop
|
2drop
|
||||||
1 validate-key
|
1 validate-key
|
||||||
0 (bye)
|
0 (bye)
|
||||||
|
|
@ -779,7 +869,7 @@
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
2 arg 2dup s" --list" compare 0= if
|
2 sarg 2dup s" --list" compare 0= if
|
||||||
2drop session-list
|
2drop session-list
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
@ -795,7 +885,7 @@
|
||||||
s" Error: --kill requires session ID" type cr
|
s" Error: --kill requires session ID" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
3 arg session-kill
|
3 sarg session-kill
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
|
|
@ -835,7 +925,7 @@
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
2 arg 2dup s" --list" compare 0= if
|
2 sarg 2dup s" --list" compare 0= if
|
||||||
2drop service-list
|
2drop service-list
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
@ -856,7 +946,7 @@
|
||||||
s" Error: --info requires service ID" type cr
|
s" Error: --info requires service ID" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
3 arg service-info
|
3 sarg service-info
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
|
|
@ -866,7 +956,7 @@
|
||||||
s" Error: --logs requires service ID" type cr
|
s" Error: --logs requires service ID" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
3 arg service-logs
|
3 sarg service-logs
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
|
|
@ -876,7 +966,7 @@
|
||||||
s" Error: --freeze requires service ID" type cr
|
s" Error: --freeze requires service ID" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
3 arg service-sleep
|
3 sarg service-sleep
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
|
|
@ -886,7 +976,7 @@
|
||||||
s" Error: --unfreeze requires service ID" type cr
|
s" Error: --unfreeze requires service ID" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
3 arg service-wake
|
3 sarg service-wake
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
|
|
@ -896,7 +986,7 @@
|
||||||
s" Error: --destroy requires service ID" type cr
|
s" Error: --destroy requires service ID" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
3 arg service-destroy
|
3 sarg service-destroy
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
|
|
@ -911,13 +1001,13 @@
|
||||||
s" Error: --resize requires --vcpu N" type cr
|
s" Error: --resize requires --vcpu N" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
4 arg 2dup s" --vcpu" compare 0= if
|
4 sarg 2dup s" --vcpu" compare 0= if
|
||||||
2drop
|
2drop
|
||||||
argc @ 6 < if
|
argc @ 6 < if
|
||||||
s" Error: --vcpu requires a value" type cr
|
s" Error: --vcpu requires a value" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
3 arg 5 arg service-resize
|
3 sarg 5 sarg service-resize
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
2dup s" -v" compare 0= if
|
2dup s" -v" compare 0= if
|
||||||
|
|
@ -926,7 +1016,7 @@
|
||||||
s" Error: -v requires a value" type cr
|
s" Error: -v requires a value" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
3 arg 5 arg service-resize
|
3 sarg 5 sarg service-resize
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
2drop
|
2drop
|
||||||
|
|
@ -940,16 +1030,16 @@
|
||||||
s" Error: --dump-bootstrap requires service ID" type cr
|
s" Error: --dump-bootstrap requires service ID" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
3 arg
|
3 sarg
|
||||||
\ Check for --dump-file
|
\ Check for --dump-file
|
||||||
argc @ 5 >= if
|
argc @ 5 >= if
|
||||||
4 arg 2dup s" --dump-file" compare 0= if
|
4 sarg 2dup s" --dump-file" compare 0= if
|
||||||
2drop
|
2drop
|
||||||
argc @ 6 < if
|
argc @ 6 < if
|
||||||
s" Error: --dump-file requires filename" type cr
|
s" Error: --dump-file requires filename" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
5 arg
|
5 sarg
|
||||||
else
|
else
|
||||||
2drop 0 0
|
2drop 0 0
|
||||||
then
|
then
|
||||||
|
|
@ -967,13 +1057,13 @@
|
||||||
s" Usage: un.forth service env <status|set|export|delete> <service_id> [options]" type cr
|
s" Usage: un.forth service env <status|set|export|delete> <service_id> [options]" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
3 arg 2dup s" status" compare 0= if
|
3 sarg 2dup s" status" compare 0= if
|
||||||
2drop
|
2drop
|
||||||
argc @ 5 < if
|
argc @ 5 < if
|
||||||
s" Error: status requires service ID" type cr
|
s" Error: status requires service ID" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
4 arg service-env-status
|
4 sarg service-env-status
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
2dup s" set" compare 0= if
|
2dup s" set" compare 0= if
|
||||||
|
|
@ -991,7 +1081,7 @@
|
||||||
s" Error: export requires service ID" type cr
|
s" Error: export requires service ID" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
4 arg service-env-export
|
4 sarg service-env-export
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
2dup s" delete" compare 0= if
|
2dup s" delete" compare 0= if
|
||||||
|
|
@ -1000,7 +1090,7 @@
|
||||||
s" Error: delete requires service ID" type cr
|
s" Error: delete requires service ID" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
4 arg service-env-delete
|
4 sarg service-env-delete
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
2drop
|
2drop
|
||||||
|
|
@ -1072,7 +1162,7 @@
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
2 arg 2dup s" --json" compare 0= if
|
2 sarg 2dup s" --json" compare 0= if
|
||||||
2drop
|
2drop
|
||||||
1 languages-list
|
1 languages-list
|
||||||
0 (bye)
|
0 (bye)
|
||||||
|
|
@ -1670,7 +1760,7 @@
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
2 arg 2dup s" --list" compare 0= if
|
2 sarg 2dup s" --list" compare 0= if
|
||||||
2drop snapshot-list
|
2drop snapshot-list
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
@ -1686,7 +1776,7 @@
|
||||||
s" Error: --info requires snapshot ID" type cr
|
s" Error: --info requires snapshot ID" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
3 arg snapshot-info
|
3 sarg snapshot-info
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
|
|
@ -1696,7 +1786,7 @@
|
||||||
s" Error: --restore requires snapshot ID" type cr
|
s" Error: --restore requires snapshot ID" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
3 arg snapshot-restore
|
3 sarg snapshot-restore
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
|
|
@ -1706,7 +1796,7 @@
|
||||||
s" Error: --delete requires snapshot ID" type cr
|
s" Error: --delete requires snapshot ID" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
3 arg snapshot-delete
|
3 sarg snapshot-delete
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
|
|
@ -1716,7 +1806,7 @@
|
||||||
s" Error: --lock requires snapshot ID" type cr
|
s" Error: --lock requires snapshot ID" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
3 arg snapshot-lock
|
3 sarg snapshot-lock
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
|
|
@ -1726,7 +1816,7 @@
|
||||||
s" Error: --unlock requires snapshot ID" type cr
|
s" Error: --unlock requires snapshot ID" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
3 arg snapshot-unlock
|
3 sarg snapshot-unlock
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
|
|
@ -1736,7 +1826,7 @@
|
||||||
s" Error: --clone requires snapshot ID" type cr
|
s" Error: --clone requires snapshot ID" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
3 arg snapshot-clone
|
3 sarg snapshot-clone
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
|
|
@ -1752,7 +1842,7 @@
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
2 arg 2dup s" --list" compare 0= if
|
2 sarg 2dup s" --list" compare 0= if
|
||||||
2drop image-list
|
2drop image-list
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
@ -1768,7 +1858,7 @@
|
||||||
s" Error: --info requires image ID" type cr
|
s" Error: --info requires image ID" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
3 arg image-info
|
3 sarg image-info
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
|
|
@ -1778,7 +1868,7 @@
|
||||||
s" Error: --delete requires image ID" type cr
|
s" Error: --delete requires image ID" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
3 arg image-delete
|
3 sarg image-delete
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
|
|
@ -1788,7 +1878,7 @@
|
||||||
s" Error: --lock requires image ID" type cr
|
s" Error: --lock requires image ID" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
3 arg image-lock
|
3 sarg image-lock
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
|
|
@ -1798,7 +1888,7 @@
|
||||||
s" Error: --unlock requires image ID" type cr
|
s" Error: --unlock requires image ID" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
3 arg image-unlock
|
3 sarg image-unlock
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
|
|
@ -1818,7 +1908,7 @@
|
||||||
s" Error: --visibility requires image ID and mode" type cr
|
s" Error: --visibility requires image ID and mode" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
3 arg 4 arg image-visibility
|
3 sarg 4 sarg image-visibility
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
|
|
@ -1828,7 +1918,7 @@
|
||||||
s" Error: --spawn requires image ID" type cr
|
s" Error: --spawn requires image ID" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
3 arg image-spawn
|
3 sarg image-spawn
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
|
|
@ -1838,7 +1928,7 @@
|
||||||
s" Error: --clone requires image ID" type cr
|
s" Error: --clone requires image ID" type cr
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
3 arg image-clone
|
3 sarg image-clone
|
||||||
0 (bye)
|
0 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
|
|
@ -1860,8 +1950,21 @@
|
||||||
1 (bye)
|
1 (bye)
|
||||||
then
|
then
|
||||||
|
|
||||||
\ Get first argument (skip gforth and script name)
|
\ Check for --account N as first argument (before arg-shift is applied)
|
||||||
1 arg
|
1 arg 2dup s" --account" compare 0= if
|
||||||
|
2drop
|
||||||
|
argc @ 3 < if
|
||||||
|
s" Error: --account requires a numeric argument" type cr
|
||||||
|
1 (bye)
|
||||||
|
then
|
||||||
|
2 arg s>number drop account-index !
|
||||||
|
2 arg-shift !
|
||||||
|
else
|
||||||
|
2drop
|
||||||
|
then
|
||||||
|
|
||||||
|
\ Get subcommand (adjusted for arg-shift)
|
||||||
|
1 arg-shift @ + arg
|
||||||
|
|
||||||
\ Check for subcommands
|
\ Check for subcommands
|
||||||
2dup s" session" compare 0= if
|
2dup s" session" compare 0= if
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,9 @@
|
||||||
|
|
||||||
:- initialization(main, main).
|
:- initialization(main, main).
|
||||||
|
|
||||||
|
% Initialize global account index to -1 (not set)
|
||||||
|
:- nb_setval(account_index, -1).
|
||||||
|
|
||||||
% Constants
|
% Constants
|
||||||
portal_base('https://unsandbox.com').
|
portal_base('https://unsandbox.com').
|
||||||
languages_cache_ttl(3600). % 1 hour cache TTL
|
languages_cache_ttl(3600). % 1 hour cache TTL
|
||||||
|
|
@ -85,26 +88,91 @@ read_file_content(Filename, Content) :-
|
||||||
read_string(Stream, _, Content),
|
read_string(Stream, _, Content),
|
||||||
close(Stream).
|
close(Stream).
|
||||||
|
|
||||||
% Get API keys from environment (HMAC or legacy)
|
% Load credentials from accounts.csv at 0-indexed row
|
||||||
|
% Tries ~/.unsandbox/accounts.csv first, then ./accounts.csv
|
||||||
|
load_accounts_csv(Index, PK, SK) :-
|
||||||
|
getenv('HOME', Home),
|
||||||
|
atomic_list_concat([Home, '/.unsandbox/accounts.csv'], Path1),
|
||||||
|
( exists_file(Path1)
|
||||||
|
-> load_accounts_csv_file(Path1, Index, PK, SK)
|
||||||
|
; exists_file('accounts.csv')
|
||||||
|
-> load_accounts_csv_file('accounts.csv', Index, PK, SK)
|
||||||
|
; fail
|
||||||
|
).
|
||||||
|
|
||||||
|
load_accounts_csv_file(Path, Index, PK, SK) :-
|
||||||
|
setup_call_cleanup(
|
||||||
|
open(Path, read, Stream),
|
||||||
|
load_accounts_csv_stream(Stream, 0, Index, PK, SK),
|
||||||
|
close(Stream)
|
||||||
|
).
|
||||||
|
|
||||||
|
load_accounts_csv_stream(Stream, Count, Index, PK, SK) :-
|
||||||
|
read_line_to_string(Stream, Line),
|
||||||
|
Line \= end_of_file,
|
||||||
|
!,
|
||||||
|
% Skip blank lines and comments
|
||||||
|
( (Line = "" ; string_code(1, Line, 35)) % 35 = '#'
|
||||||
|
-> load_accounts_csv_stream(Stream, Count, Index, PK, SK)
|
||||||
|
; Count =:= Index
|
||||||
|
-> split_string(Line, ",", " \t", [PKStr, SKStr|_]),
|
||||||
|
atom_string(PK, PKStr),
|
||||||
|
atom_string(SK, SKStr)
|
||||||
|
; Next is Count + 1,
|
||||||
|
load_accounts_csv_stream(Stream, Next, Index, PK, SK)
|
||||||
|
).
|
||||||
|
|
||||||
|
% Get API keys from environment (HMAC or legacy), respecting --account N
|
||||||
get_public_key(PublicKey) :-
|
get_public_key(PublicKey) :-
|
||||||
( getenv('UNSANDBOX_PUBLIC_KEY', PublicKey),
|
( nb_getval(account_index, Idx), Idx >= 0
|
||||||
|
-> ( load_accounts_csv(Idx, PublicKey, _)
|
||||||
|
-> true
|
||||||
|
; format(user_error, 'Error: Account index ~w not found in accounts.csv~n', [Idx]),
|
||||||
|
halt(1)
|
||||||
|
)
|
||||||
|
; ( getenv('UNSANDBOX_PUBLIC_KEY', PublicKey),
|
||||||
PublicKey \= ''
|
PublicKey \= ''
|
||||||
-> true
|
-> true
|
||||||
; getenv('UNSANDBOX_API_KEY', PublicKey),
|
; getenv('UNSANDBOX_API_KEY', PublicKey),
|
||||||
PublicKey \= ''
|
PublicKey \= ''
|
||||||
-> true
|
-> true
|
||||||
|
; % Try accounts.csv with UNSANDBOX_ACCOUNT or row 0
|
||||||
|
( getenv('UNSANDBOX_ACCOUNT', IdxStr),
|
||||||
|
atom_number(IdxStr, DefaultIdx)
|
||||||
|
-> true
|
||||||
|
; DefaultIdx = 0
|
||||||
|
),
|
||||||
|
( load_accounts_csv(DefaultIdx, PublicKey, _)
|
||||||
|
-> true
|
||||||
; write(user_error, 'Error: UNSANDBOX_PUBLIC_KEY or UNSANDBOX_API_KEY environment variable not set\n'),
|
; write(user_error, 'Error: UNSANDBOX_PUBLIC_KEY or UNSANDBOX_API_KEY environment variable not set\n'),
|
||||||
halt(1)
|
halt(1)
|
||||||
|
)
|
||||||
|
)
|
||||||
).
|
).
|
||||||
|
|
||||||
get_secret_key(SecretKey) :-
|
get_secret_key(SecretKey) :-
|
||||||
( getenv('UNSANDBOX_SECRET_KEY', SecretKey),
|
( nb_getval(account_index, Idx), Idx >= 0
|
||||||
|
-> ( load_accounts_csv(Idx, _, SecretKey)
|
||||||
|
-> true
|
||||||
|
; SecretKey = ''
|
||||||
|
)
|
||||||
|
; ( getenv('UNSANDBOX_SECRET_KEY', SecretKey),
|
||||||
SecretKey \= ''
|
SecretKey \= ''
|
||||||
-> true
|
-> true
|
||||||
; getenv('UNSANDBOX_API_KEY', SecretKey),
|
; getenv('UNSANDBOX_API_KEY', SecretKey),
|
||||||
SecretKey \= ''
|
SecretKey \= ''
|
||||||
-> true
|
-> true
|
||||||
|
; % Try accounts.csv with UNSANDBOX_ACCOUNT or row 0
|
||||||
|
( getenv('UNSANDBOX_ACCOUNT', IdxStr),
|
||||||
|
atom_number(IdxStr, DefaultIdx)
|
||||||
|
-> true
|
||||||
|
; DefaultIdx = 0
|
||||||
|
),
|
||||||
|
( load_accounts_csv(DefaultIdx, _, SecretKey)
|
||||||
|
-> true
|
||||||
; SecretKey = ''
|
; SecretKey = ''
|
||||||
|
)
|
||||||
|
)
|
||||||
).
|
).
|
||||||
|
|
||||||
% Get API key (legacy compatibility)
|
% Get API key (legacy compatibility)
|
||||||
|
|
@ -742,8 +810,22 @@ service_create_with_vault(Name, Ports, Bootstrap, BootstrapFile, ServiceType, In
|
||||||
|
|
||||||
% Main program
|
% Main program
|
||||||
main(Argv) :-
|
main(Argv) :-
|
||||||
|
% Initialize account_index global to -1 (not set)
|
||||||
|
nb_setval(account_index, -1),
|
||||||
|
|
||||||
|
% Parse --account N global flag if present
|
||||||
|
( Argv = ['--account', NStr|Rest]
|
||||||
|
-> ( atom_number(NStr, N), integer(N)
|
||||||
|
-> nb_setval(account_index, N),
|
||||||
|
ActualArgv = Rest
|
||||||
|
; write(user_error, 'Error: --account requires an integer argument\n'),
|
||||||
|
halt(1)
|
||||||
|
)
|
||||||
|
; ActualArgv = Argv
|
||||||
|
),
|
||||||
|
|
||||||
% Check arguments
|
% Check arguments
|
||||||
( Argv = []
|
( ActualArgv = []
|
||||||
-> write(user_error, 'Usage: un.pro [options] <source_file>\n'),
|
-> write(user_error, 'Usage: un.pro [options] <source_file>\n'),
|
||||||
write(user_error, ' un.pro session [options]\n'),
|
write(user_error, ' un.pro session [options]\n'),
|
||||||
write(user_error, ' un.pro service [options]\n'),
|
write(user_error, ' un.pro service [options]\n'),
|
||||||
|
|
@ -782,19 +864,19 @@ main(Argv) :-
|
||||||
),
|
),
|
||||||
|
|
||||||
% Parse subcommands
|
% Parse subcommands
|
||||||
( Argv = ['session'|Rest]
|
( ActualArgv = ['session'|Rest]
|
||||||
-> handle_session(Rest)
|
-> handle_session(Rest)
|
||||||
; Argv = ['service'|Rest]
|
; ActualArgv = ['service'|Rest]
|
||||||
-> handle_service(Rest)
|
-> handle_service(Rest)
|
||||||
; Argv = ['snapshot'|Rest]
|
; ActualArgv = ['snapshot'|Rest]
|
||||||
-> handle_snapshot(Rest)
|
-> handle_snapshot(Rest)
|
||||||
; Argv = ['image'|Rest]
|
; ActualArgv = ['image'|Rest]
|
||||||
-> handle_image(Rest)
|
-> handle_image(Rest)
|
||||||
; Argv = ['languages'|Rest]
|
; ActualArgv = ['languages'|Rest]
|
||||||
-> handle_languages(Rest)
|
-> handle_languages(Rest)
|
||||||
; Argv = ['key'|Rest]
|
; ActualArgv = ['key'|Rest]
|
||||||
-> handle_key(Rest)
|
-> handle_key(Rest)
|
||||||
; Argv = [Filename|_]
|
; ActualArgv = [Filename|_]
|
||||||
-> execute_file(Filename)
|
-> execute_file(Filename)
|
||||||
; write(user_error, 'Error: Invalid arguments\n'),
|
; write(user_error, 'Error: Invalid arguments\n'),
|
||||||
halt(1)
|
halt(1)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue