Fix Crystal test class variables and V implementation syntax

- Crystal: Wrap class variables in TestCounter class (top-level @@ not allowed)
- V: Fix deprecated const() syntax to individual const declarations
- V: Fix os.execute or-blocks to use exit_code checks
- V: Fix shell variable escaping (use $ for literal $ in shell strings)
- README: Add unit test documentation and CI badge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Russell Ballestrini 2026-01-06 09:57:49 -05:00
parent 160740e1ea
commit 9329d9365f
3 changed files with 94 additions and 38 deletions

View file

@ -179,6 +179,36 @@ Each implementation supports:
./tests/run_all_tests.sh ./tests/run_all_tests.sh
``` ```
### Unit Tests
Every implementation has unit tests that verify core functionality without requiring API calls:
```bash
# Run unit tests for any language
python3 tests/unit/test_python.py
node tests/unit/test_javascript.js
ruby tests/unit/test_ruby.rb
go test -v tests/unit/test_go.go
julia tests/unit/test_julia.jl
elixir tests/unit/test_elixir.exs
```
Unit tests cover:
- **Extension mapping** - File extensions map to correct languages
- **HMAC signatures** - SHA256 signing produces valid 64-char hex strings
- **Signature format** - Message format is `timestamp:METHOD:path:body`
- **Language detection** - Shebang parsing and extension detection
- **Argument parsing** - `-e KEY=VALUE` format handling
- **File operations** - Base64 encoding, path extraction
### CI/CD
GitHub Actions runs the full test matrix on every push:
[![Inception Matrix](https://github.com/russellballestrini/un-inception/actions/workflows/inception-matrix.yml/badge.svg)](https://github.com/russellballestrini/un-inception/actions/workflows/inception-matrix.yml)
The workflow tests all 42 implementations across their respective runtimes.
## The Inception Matrix ## The Inception Matrix
**Use un to run un inside un!** Don't have a language installed locally? Run its implementation through unsandbox using `un` (the C implementation): **Use un to run un inside un!** Don't have a language installed locally? Run its implementation through unsandbox using `un` (the C implementation):

View file

@ -11,9 +11,27 @@ RED = "\033[31m"
BLUE = "\033[34m" BLUE = "\033[34m"
RESET = "\033[0m" RESET = "\033[0m"
# Test counters # Test counters - use class with class variables
@@passed = 0 class TestCounter
@@failed = 0 @@passed = 0
@@failed = 0
def self.passed
@@passed
end
def self.failed
@@failed
end
def self.inc_passed
@@passed += 1
end
def self.inc_failed
@@failed += 1
end
end
# Extension to language mapping (from un.cr) # Extension to language mapping (from un.cr)
EXT_MAP = { EXT_MAP = {
@ -44,10 +62,10 @@ end
def print_test(name : String, result : Bool) def print_test(name : String, result : Bool)
if result if result
puts "#{GREEN}✓ PASS#{RESET}: #{name}" puts "#{GREEN}✓ PASS#{RESET}: #{name}"
@@passed += 1 TestCounter.inc_passed
else else
puts "#{RED}✗ FAIL#{RESET}: #{name}" puts "#{RED}✗ FAIL#{RESET}: #{name}"
@@failed += 1 TestCounter.inc_failed
end end
end end
@ -143,11 +161,11 @@ print_test("Multiple dots in filename", detect_language("my.test.py") == "python
puts "\n#{BLUE}========================================#{RESET}" puts "\n#{BLUE}========================================#{RESET}"
puts "#{BLUE}Test Summary#{RESET}" puts "#{BLUE}Test Summary#{RESET}"
puts "#{BLUE}========================================#{RESET}" puts "#{BLUE}========================================#{RESET}"
puts "#{GREEN}Passed: #{@@passed}#{RESET}" puts "#{GREEN}Passed: #{TestCounter.passed}#{RESET}"
puts "#{RED}Failed: #{@@failed}#{RESET}" puts "#{RED}Failed: #{TestCounter.failed}#{RESET}"
puts "#{BLUE}Total: #{@@passed + @@failed}#{RESET}" puts "#{BLUE}Total: #{TestCounter.passed + TestCounter.failed}#{RESET}"
if @@failed > 0 if TestCounter.failed > 0
puts "\n#{RED}TESTS FAILED#{RESET}" puts "\n#{RED}TESTS FAILED#{RESET}"
exit 1 exit 1
else else

66
un.v
View file

@ -45,15 +45,13 @@
import os import os
const ( const api_base = 'https://api.unsandbox.com'
api_base = 'https://api.unsandbox.com' const portal_base = 'https://unsandbox.com'
portal_base = 'https://unsandbox.com' const blue = '\x1b[34m'
blue = '\x1b[34m' const red = '\x1b[31m'
red = '\x1b[31m' const green = '\x1b[32m'
green = '\x1b[32m' const yellow = '\x1b[33m'
yellow = '\x1b[33m' const reset = '\x1b[0m'
reset = '\x1b[0m'
)
fn detect_language(filename string) !string { fn detect_language(filename string) !string {
ext := os.file_ext(filename) ext := os.file_ext(filename)
@ -162,7 +160,7 @@ fn cmd_key(extend bool, api_key string) {
pub_key := get_public_key() pub_key := get_public_key()
secret_key := get_secret_key() secret_key := get_secret_key()
body := '{}' body := '{}'
cmd := "BODY='${body}'; TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:POST:/keys/validate:\\$BODY\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${portal_base}/keys/validate' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\" -d \"\\$BODY\"" cmd := "BODY='${body}'; TIMESTAMP=\$\$(date +%s); MESSAGE=\"\$\$TIMESTAMP:POST:/keys/validate:\$\$BODY\"; SIGNATURE=\$\$(echo -n \"\$\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${portal_base}/keys/validate' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \$\$TIMESTAMP\" -H \"X-Signature: \$\$SIGNATURE\" -d \"\$\$BODY\""
result := exec_curl(cmd) result := exec_curl(cmd)
public_key := extract_json_string(result, 'public_key') public_key := extract_json_string(result, 'public_key')
@ -180,11 +178,21 @@ fn cmd_key(extend bool, api_key string) {
println('${blue}Opening browser to extend key...${reset}') println('${blue}Opening browser to extend key...${reset}')
// Try xdg-open (Linux), open (macOS), or start (Windows) // Try xdg-open (Linux), open (macOS), or start (Windows)
os.execute('xdg-open "${url}"') or { mut opened := false
os.execute('open "${url}"') or { result := os.execute('xdg-open "${url}"')
os.execute('cmd /c start "${url}"') or { if result.exit_code == 0 {
eprintln('${red}Error: Could not open browser${reset}') opened = true
} }
if !opened {
result2 := os.execute('open "${url}"')
if result2.exit_code == 0 {
opened = true
}
}
if !opened {
result3 := os.execute('cmd /c start "${url}"')
if result3.exit_code != 0 {
eprintln('${red}Error: Could not open browser${reset}')
} }
} }
return return
@ -267,7 +275,7 @@ fn cmd_execute(source_file string, envs []string, artifacts bool, network string
pub_key := get_public_key() pub_key := get_public_key()
secret_key := get_secret_key() secret_key := get_secret_key()
cmd := "BODY='${json}'; TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:POST:/execute:\\$BODY\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/execute' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\" -d \"\\$BODY\"" cmd := "BODY='${json}'; TIMESTAMP=\$\$(date +%s); MESSAGE=\"\$\$TIMESTAMP:POST:/execute:\$\$BODY\"; SIGNATURE=\$\$(echo -n \"\$\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/execute' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \$\$TIMESTAMP\" -H \"X-Signature: \$\$SIGNATURE\" -d \"\$\$BODY\""
println(exec_curl(cmd)) println(exec_curl(cmd))
} }
@ -276,13 +284,13 @@ fn cmd_session(list bool, kill string, shell string, network string, vcpu int, t
secret_key := get_secret_key() secret_key := get_secret_key()
if list { if list {
cmd := "TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:GET:/sessions:\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X GET '${api_base}/sessions' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\"" cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:GET:/sessions:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X GET '${api_base}/sessions' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
println(exec_curl(cmd)) println(exec_curl(cmd))
return return
} }
if kill != '' { if kill != '' {
cmd := "TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:DELETE:/sessions/${kill}:\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X DELETE '${api_base}/sessions/${kill}' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\"" cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:DELETE:/sessions/${kill}:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X DELETE '${api_base}/sessions/${kill}' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
exec_curl(cmd) exec_curl(cmd)
println('${green}Session terminated: ${kill}${reset}') println('${green}Session terminated: ${kill}${reset}')
return return
@ -306,7 +314,7 @@ fn cmd_session(list bool, kill string, shell string, network string, vcpu int, t
json += '}' json += '}'
println('${yellow}Creating session...${reset}') println('${yellow}Creating session...${reset}')
cmd := "BODY='${json}'; TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:POST:/sessions:\\$BODY\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/sessions' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\" -d \"\\$BODY\"" cmd := "BODY='${json}'; TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:POST:/sessions:$$BODY\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/sessions' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\" -d \"$$BODY\""
println(exec_curl(cmd)) println(exec_curl(cmd))
} }
@ -315,45 +323,45 @@ fn cmd_service(name string, ports string, service_type string, bootstrap string,
secret_key := get_secret_key() secret_key := get_secret_key()
if list { if list {
cmd := "TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:GET:/services:\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X GET '${api_base}/services' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\"" cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:GET:/services:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X GET '${api_base}/services' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
println(exec_curl(cmd)) println(exec_curl(cmd))
return return
} }
if info != '' { if info != '' {
cmd := "TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:GET:/services/${info}:\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X GET '${api_base}/services/${info}' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\"" cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:GET:/services/${info}:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X GET '${api_base}/services/${info}' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
println(exec_curl(cmd)) println(exec_curl(cmd))
return return
} }
if logs != '' { if logs != '' {
cmd := "TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:GET:/services/${logs}/logs:\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X GET '${api_base}/services/${logs}/logs' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\"" cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:GET:/services/${logs}/logs:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X GET '${api_base}/services/${logs}/logs' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
print(exec_curl(cmd)) print(exec_curl(cmd))
return return
} }
if tail != '' { if tail != '' {
cmd := "TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:GET:/services/${tail}/logs:\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X GET '${api_base}/services/${tail}/logs?lines=9000' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\"" cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:GET:/services/${tail}/logs:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X GET '${api_base}/services/${tail}/logs?lines=9000' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
print(exec_curl(cmd)) print(exec_curl(cmd))
return return
} }
if sleep != '' { if sleep != '' {
cmd := "TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:POST:/services/${sleep}/sleep:\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/services/${sleep}/sleep' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\"" cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:POST:/services/${sleep}/sleep:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/services/${sleep}/sleep' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
exec_curl(cmd) exec_curl(cmd)
println('${green}Service sleeping: ${sleep}${reset}') println('${green}Service sleeping: ${sleep}${reset}')
return return
} }
if wake != '' { if wake != '' {
cmd := "TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:POST:/services/${wake}/wake:\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/services/${wake}/wake' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\"" cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:POST:/services/${wake}/wake:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/services/${wake}/wake' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
exec_curl(cmd) exec_curl(cmd)
println('${green}Service waking: ${wake}${reset}') println('${green}Service waking: ${wake}${reset}')
return return
} }
if destroy != '' { if destroy != '' {
cmd := "TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:DELETE:/services/${destroy}:\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X DELETE '${api_base}/services/${destroy}' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\"" cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:DELETE:/services/${destroy}:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X DELETE '${api_base}/services/${destroy}' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
exec_curl(cmd) exec_curl(cmd)
println('${green}Service destroyed: ${destroy}${reset}') println('${green}Service destroyed: ${destroy}${reset}')
return return
@ -361,7 +369,7 @@ fn cmd_service(name string, ports string, service_type string, bootstrap string,
if execute != '' { if execute != '' {
json := '{"command":"${escape_json(command)}"}' json := '{"command":"${escape_json(command)}"}'
cmd := "BODY='${json}'; TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:POST:/services/${execute}/execute:\\$BODY\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/services/${execute}/execute' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\" -d \"\\$BODY\"" cmd := "BODY='${json}'; TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:POST:/services/${execute}/execute:$$BODY\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/services/${execute}/execute' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\" -d \"$$BODY\""
result := exec_curl(cmd) result := exec_curl(cmd)
stdout_str := extract_json_string(result, 'stdout') stdout_str := extract_json_string(result, 'stdout')
@ -378,7 +386,7 @@ fn cmd_service(name string, ports string, service_type string, bootstrap string,
if dump_bootstrap != '' { if dump_bootstrap != '' {
eprintln('Fetching bootstrap script from ${dump_bootstrap}...') eprintln('Fetching bootstrap script from ${dump_bootstrap}...')
json := '{"command":"cat /tmp/bootstrap.sh"}' json := '{"command":"cat /tmp/bootstrap.sh"}'
cmd := "BODY='${json}'; TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:POST:/services/${dump_bootstrap}/execute:\\$BODY\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/services/${dump_bootstrap}/execute' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\" -d \"\\$BODY\"" cmd := "BODY='${json}'; TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:POST:/services/${dump_bootstrap}/execute:$$BODY\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/services/${dump_bootstrap}/execute' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\" -d \"$$BODY\""
result := exec_curl(cmd) result := exec_curl(cmd)
bootstrap_script := extract_json_string(result, 'stdout') bootstrap_script := extract_json_string(result, 'stdout')
@ -433,7 +441,7 @@ fn cmd_service(name string, ports string, service_type string, bootstrap string,
json += '}' json += '}'
println('${yellow}Creating service...${reset}') println('${yellow}Creating service...${reset}')
cmd := "BODY='${json}'; TIMESTAMP=\\$(date +%s); MESSAGE=\"\\$TIMESTAMP:POST:/services:\\$BODY\"; SIGNATURE=\\$(echo -n \"\\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/services' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \\$TIMESTAMP\" -H \"X-Signature: \\$SIGNATURE\" -d \"\\$BODY\"" cmd := "BODY='${json}'; TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:POST:/services:$$BODY\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/services' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\" -d \"$$BODY\""
println(exec_curl(cmd)) println(exec_curl(cmd))
return return
} }