diff --git a/.gitignore b/.gitignore index 190c097c3..6b487ce1c 100644 --- a/.gitignore +++ b/.gitignore @@ -44,5 +44,4 @@ nitro-shim/tools/eifbuild/third_party/** nitro-image.eif bat-go-repro.tar -# File with test keys -/payments-test-secretes.json +/build/ diff --git a/Makefile b/Makefile index 8da13b285..2b46ae531 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,10 @@ codeql: download-mod buildcmd buildcmd: cd main && CGO_ENABLED=0 GOOS=$(GOOS) GOARCH=$(GOARCH) go build -ldflags "-w -s -X main.version=${GIT_VERSION} -X main.buildTime=${BUILD_TIME} -X main.commit=${GIT_COMMIT}" -o ${OUTPUT}/bat-go main.go +builddev: + test -d build || mkdir build + cd main && go build -o ../build/bat-go main.go + mock: cd services && mockgen -source=./promotion/claim.go -destination=promotion/mockclaim.go -package=promotion cd services && mockgen -source=./promotion/drain.go -destination=promotion/mockdrain.go -package=promotion @@ -102,7 +106,7 @@ docker: docker tag bat-go:$(GIT_VERSION)$(BUILD_TIME) bat-go:latest docker-local: - docker build -t bat-go-local -f local-dev/local.dockerfile --target image . + docker build -t bat-go-local -f local-dev/local.dockerfile . docker-reproducible: $(eval TMP_CHECKOUT = $(shell mktemp -d 2>/dev/null || mktemp -d -t 'bat-go-tmp')) diff --git a/docker-compose.payments.yml b/docker-compose.payments.yml index c49e419ce..84e712493 100644 --- a/docker-compose.payments.yml +++ b/docker-compose.payments.yml @@ -3,8 +3,8 @@ services: image: redis:7.0 restart: always #ports: - # - '6379:6379' - command: redis-server --save 20 1 --loglevel verbose --requirepass testpass --user redis + # - '6380:6380' + command: redis-server --save 20 1 --loglevel verbose --requirepass testpass --user redis --port 6380 #volumes: # - redis-cache:/data @@ -17,7 +17,7 @@ services: localstack: container_name: localstack image: localstack/localstack - stop_grace_period: 1s + stop_grace_period: "1s" ports: - "127.0.0.1:4566:4566" # LocalStack Gateway - "127.0.0.1:4510-4559:4510-4559" # external services port range @@ -31,13 +31,19 @@ services: worker: image: bat-go-local - command: /build/bat-go serve payments worker depends_on: - redis - localstack + volumes: + - .:/workspace + command: >- + /workspace/local-dev/run-as-workspace-user.sh + /workspace/local-dev/run-until-rebuild.sh + /workspace/build/bat-go serve payments worker + restart: unless-stopped environment: - NITRO_ENCLAVE_MOCKING=1 - - REDIS_ADDR=redis:6379 + - REDIS_ADDR=redis:6380 - REDIS_USER=default - REDIS_PASS=testpass - DEBUG=1 @@ -46,11 +52,22 @@ services: service: image: bat-go-local - command: /build/bat-go serve nitro inside-enclave --egress-address none --log-address none --upstream-url http://0.0.0.0:8080 + depends_on: + - redis + - localstack volumes: - - ./payments-test-secretes.json:/etc/bat-test-secretes.json:ro + - .:/workspace + command: >- + /workspace/local-dev/run-as-workspace-user.sh + /workspace/local-dev/run-until-rebuild.sh + /workspace/build/bat-go serve nitro inside-enclave + --egress-address none --log-address none + --upstream-url http://0.0.0.0:8080 + working_dir: /workspace + restart: unless-stopped environment: - NITRO_ENCLAVE_MOCKING=1 + - BAT_PAYMENT_TEST_SECRETS=/workspace/local-dev/secrets/payments-test.json - DEBUG=1 - ADDR=0.0.0.0:18080 - ADDR2=0.0.0.0:18443 @@ -58,7 +75,7 @@ services: - QLDB_LEDGER_ARN=arn:aws:qldb:us-west-2:239563960694:ledger/testing-igor-payment - QLDB_LEDGER_NAME=testing-igor-payment - QLDB_ROLE_ARN=arn:aws:iam::239563960694:role/settlements-dev-sso-qldb-20240628161845683100000001 - - AWS_REGION=${AWS_REGION-} + - AWS_REGION=${AWS_REGION-us-west-2} - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID-} - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY-} - AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN-} @@ -69,6 +86,36 @@ services: - "127.0.0.1:18080:18080" - "127.0.0.1:18443:18443" + shell: + image: bat-go-local + depends_on: + - redis + - localstack + volumes: + - .:/workspace + stop_grace_period: "1s" + # The shell uses localhost for redis by default, so use the redis container + # network for that to work. + network_mode: "service:redis" + command: >- + /workspace/local-dev/run-as-workspace-user.sh + ipython3 --profile-dir=ipython-profile + working_dir: /workspace/tools/payments + stdin_open: true + tty: true + environment: + - NITRO_ENCLAVE_MOCKING=1 + - DEBUG=1 + - REDIS_ADDR=redis:6379 + - REDIS_USERNAME=default + - REDIS_PASSWORD=testpass + - AWS_REGION=${AWS_REGION-us-west-2} + - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID-} + - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY-} + - AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN-} + - AWS_CONTAINER_CREDENTIALS_FULL_URI=${AWS_CONTAINER_CREDENTIALS_FULL_URI-} + - AWS_CONTAINER_AUTHORIZATION_TOKEN=${AWS_CONTAINER_AUTHORIZATION_TOKEN-} + volumes: redis-cache: driver: local diff --git a/local-dev/.gitignore b/local-dev/.gitignore new file mode 100644 index 000000000..dcb4f1052 --- /dev/null +++ b/local-dev/.gitignore @@ -0,0 +1,5 @@ +# Local files with development scretes. +/secrets/ + +# Home in the container +/home/ diff --git a/local-dev/ensure-secretes.sh b/local-dev/ensure-secretes.sh new file mode 100755 index 000000000..c5b3e59c3 --- /dev/null +++ b/local-dev/ensure-secretes.sh @@ -0,0 +1,47 @@ +#!/bin/sh + +set -eu + +self="$(realpath "$0")" +secrets="${self%/*}/secrets" + +test -d "$secrets" || { + echo "Creating $secrets directory" >&2 + mkdir -m 0700 "$secrets" +} + +f="$secrets/payments-test.json" +test -s "$f" || { + echo "The file with configuration keys $f does not exist or empty, please obtain it" + exit 1 +} + +# We need to generate ED25519 key in PEM format and its public key in OpenSSH +# format. Unfortunately ssh-keygen released only 2024 supports. So use a +# workaround. + +pem="$secrets/payment-test-operator.pem" +test -s "$pem" || { + echo "ED25519 private key file $pem does not exist, generating it" >&2 + x="$(command -v openssl 2>/dev/null || :)" + test "$x" || { + echo "openssl tool does not exist, please install it. On Debian-based system use:" >&2 + echo " apt install openssl" >&2 + exit 1 + } + rm -f "$pem.tmp" + openssl genpkey -algorithm ed25519 > "$pem.tmp" + mv "$pem.tmp" "$pem" +} +pub="${pem%.pem}.pub" +test -s "$pub" || { + echo "ED25519 public key file $pub does not exist, producing it from" >&2 + x="$(command -v sshpk-conv 2>/dev/null || :)" + test "$x" || { + echo "sshpk-conv utility does not exist, please install it. On Debian-based system use:" >&2 + echo " apt install node-sshpk" >&2 + exit 1 + } + sshpk-conv -T pem -t ssh -f "$pem" -o "$pub" +} + diff --git a/local-dev/local.dockerfile b/local-dev/local.dockerfile index cfba5c274..c06e59ef5 100644 --- a/local-dev/local.dockerfile +++ b/local-dev/local.dockerfile @@ -1,12 +1,16 @@ -FROM debian:bookworm AS base +FROM debian:bookworm ARG DEBIAN_FRONTEND=noninteractive ARG GOLANG_VERSION=1.22.4 RUN apt-get update \ && apt-get install -y -qq \ - tmux curl man less \ - python3 git make + tmux curl man less openssh-client openssl util-linux \ + python3 ipython3 python-is-python3 \ + socat lsof wget diffutils \ + git make \ + redis-tools \ + node-sshpk # Install Go RUN set -x && curl -L -o /var/tmp/go.tgz \ @@ -16,37 +20,5 @@ RUN set -x && curl -L -o /var/tmp/go.tgz \ && find /usr/local/go/bin -type f -perm /001 \ -exec ln -s -t /usr/local/bin '{}' + -RUN useradd -m user - -RUN mkdir /build && chown user:user /build - -USER user -WORKDIR /home/user - -#CMD [ "sleep", "infinity" ] - -# A helper stage to hold Go sources with go.mod and related infrequently changed -# files moved to separated directory so they can be copied later before the *.go -# files to allow to cache downloaded Go modules in a Docker layer independent -# from more frequently changed sources. -FROM base as sources - -COPY --chown=user:user . /build/repo -RUN mkdir /build/mod-files && cd /build/repo && rm -rf .git \ - && find . -name go.\* | xargs tar cf - | tar -C /build/mod-files -xf - \ - && find . -name go.\* -delete - -FROM base as image - -RUN mkdir -p .cache - -COPY --link --from=sources --chown=user:user /build/mod-files/ /build/src/ - -RUN cd /build/src/main && go mod download -x - -COPY --link --from=sources --chown=user:user /build/repo/ /build/src/ - -RUN cd /build/src/main \ - && CGO_ENABLED=0 GOOS=linux go build \ - -o /build/bat-go main.go - +# Use arbitrary id, not 1000, to always test the code to sync the user id. +RUN useradd -m -u 12345 user diff --git a/local-dev/run-as-workspace-user.sh b/local-dev/run-as-workspace-user.sh new file mode 100755 index 000000000..979e090b2 --- /dev/null +++ b/local-dev/run-as-workspace-user.sh @@ -0,0 +1,37 @@ +#!/bin/sh + +# Helper to sync the container user with the id of the owner of workspace and +# then run the command as that user. + +set -eu + +workspace_uid_gid="$(stat -c %u:%g /workspace)" +uid="${workspace_uid_gid%:*}" +gid="${workspace_uid_gid#*:}" + +h="/workspace/local-dev/home" + +if ! test -h /home/user; then + # The user in the container not yet adjusted + groupmod -g "$gid" user + usermod -u "$uid" user + + # Updating files inside /workspace may race with other containers. So to + # copy skeleton first copy it to a temporeary location and then move + # atomically. + if ! test -d "$h"; then + echo "Creating $h" >&2 + chown -R user:user /home/user + tmp="$(mktemp -u -p "${h%/*}")" + cp -a /home/user "$tmp" || { rm -rf "$tmp"; exit 1; } + mv "$tmp" "$h" || { rm -rf "$tmp"; exit 1; } + fi + rm -rf /home/user + ln -s "$h" /home/user +fi + +# We want to keep the current environmnet for the subprocess so we do not use +# --reset-env with setprov. Rather we just fixup few variables using env. +exec setpriv --init-groups --regid "$gid" --reuid "$uid" --no-new-privs \ + env HOME="$h" SHELL=/usr/bin/bash USER=user LOGNAME=user \ + PATH=/usr/local/bin:/usr/bin "$@" diff --git a/local-dev/run-until-rebuild.sh b/local-dev/run-until-rebuild.sh new file mode 100755 index 000000000..45c95be08 --- /dev/null +++ b/local-dev/run-until-rebuild.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +# Helper to run a command with its arguments until the timestamp of its +# executable changes. + +set -eu + +target="$1" + +test -x "$1" || { + echo "The argument $1 is not an executable" >&2 + exit 1 +} + +monitor() { + local modification_time t + modification_time="$(stat -c "%Y" "$target")" + while :; do + sleep 1 + t="$(stat -c "%Y" "$target")" + if test "$t" -ne "$modification_time"; then + echo "Newer $target is detected, restarting" >&2 + kill "$$" + sleep 0.5 + kill -9 "$$" + fi + done +} + +monitor & + +bar="======================================================================" +t="$(date '+%Y-%m-%d %H:%M:%S')" +printf '%s\n[%s] Running\n[%s] %s\n%s\n' "$bar" "$t" "$t" "$*" "$bar" >&2 + +exec "$@" diff --git a/services/payments/authorize.go b/services/payments/authorize.go index 35c2cbb40..e70670aac 100644 --- a/services/payments/authorize.go +++ b/services/payments/authorize.go @@ -5,9 +5,11 @@ import ( "crypto/ed25519" "encoding/hex" "fmt" + "os" "strings" "github.com/brave-intl/bat-go/libs/httpsignature" + "github.com/brave-intl/bat-go/libs/nitro" paymentLib "github.com/brave-intl/bat-go/libs/payments" "golang.org/x/crypto/ssh" ) @@ -24,6 +26,17 @@ func init() { validAuthorizers[hex.EncodeToString(pub)] = pub } fmt.Println(validAuthorizers) + if nitro.EnclaveMocking() { + keyBytes, err := os.ReadFile("/workspace/local-dev/secrets/payment-test-operator.pub") + if err != nil { + panic(err) + } + pub, err := DecodePublicKey(string(keyBytes)) + if err != nil { + panic(err) + } + validAuthorizers[hex.EncodeToString(pub)] = pub + } } // DecodePublicKey decodes the public key which can either be a raw hex encoded ed25519 public key or an ssh-ed25519 public key diff --git a/services/payments/secrets.go b/services/payments/secrets.go index 938b52547..0172fdd4b 100644 --- a/services/payments/secrets.go +++ b/services/payments/secrets.go @@ -565,16 +565,20 @@ func (u *Unsealing) decryptSecrets(ctx context.Context) error { } func (u *Unsealing) readTestSecretes() error { - testPath := "/etc/bat-test-secretes.json" - f, err := os.Open(testPath) + envName := "BAT_PAYMENT_TEST_SECRETS" + secretsPath := os.Getenv(envName) + if secretsPath == "" { + return fmt.Errorf("The environment variable %s is not set", envName) + } + f, err := os.Open(secretsPath) if err != nil { - return err + return fmt.Errorf("Failed to open the test secrets from %s - %w", envName, err) } output := map[string]string{} if err := json.NewDecoder(f).Decode(&output); err != nil { return fmt.Errorf( - "failed to json decode the test secretes %s: %w", testPath, err) + "failed to json decode the test secretes %s: %w", secretsPath, err) } u.secrets = output return nil diff --git a/tools/payments/client.go b/tools/payments/client.go index 4075ea216..d5a1036f9 100644 --- a/tools/payments/client.go +++ b/tools/payments/client.go @@ -15,6 +15,7 @@ import ( appctx "github.com/brave-intl/bat-go/libs/context" "github.com/brave-intl/bat-go/libs/httpsignature" "github.com/brave-intl/bat-go/libs/logging" + "github.com/brave-intl/bat-go/libs/nitro" "github.com/brave-intl/bat-go/libs/payments" "github.com/brave-intl/bat-go/libs/redisconsumer" "github.com/brave-intl/bat-go/libs/requestutils" @@ -54,6 +55,10 @@ type SettlementClient interface { func NewSettlementClient(ctx context.Context, env string, config map[string]string) (context.Context, SettlementClient, error) { ctx, _ = logging.SetupLogger(ctx) + if nitro.EnclaveMocking() { + + } + var sp httpsignature.SignatureParams sp.Algorithm = httpsignature.AWSNITRO sp.KeyID = "primary" @@ -231,18 +236,20 @@ func (rc *redisClient) HandlePrepareResponse(ctx context.Context, stream, id str if err != nil { return err } - nitroVerifier, ok := rc.verifier.(httpsignature.NitroVerifier) - if !ok { - return nil - } - nitroVerifier.Now = func() time.Time { return headerDate } + if !nitro.EnclaveMocking() { + nitroVerifier, ok := rc.verifier.(httpsignature.NitroVerifier) + if !ok { + return nil + } + nitroVerifier.Now = func() time.Time { return headerDate } - valid, err := rc.sp.VerifyResponse(nitroVerifier, crypto.Hash(0), &resp) - if err != nil { - return err - } - if !valid { - return errors.New("http signature was not valid, nitro attestation failed") + valid, err := rc.sp.VerifyResponse(nitroVerifier, crypto.Hash(0), &resp) + if err != nil { + return err + } + if !valid { + return errors.New("http signature was not valid, nitro attestation failed") + } } bodyBytes, err := requestutils.Read(ctx, resp.Body) diff --git a/tools/payments/ipython-profile/ipython_config.py b/tools/payments/ipython-profile/ipython_config.py index ede5ddf4a..7606dfa3e 100644 --- a/tools/payments/ipython-profile/ipython_config.py +++ b/tools/payments/ipython-profile/ipython_config.py @@ -5,13 +5,13 @@ # InteractiveShellApp(Configurable) configuration #------------------------------------------------------------------------------ ## A Mixin for applications that start InteractiveShell instances. -# +# # Provides configurables for loading extensions and executing files # as part of configuring a Shell environment. -# +# # The following methods should be called by the :meth:`initialize` method # of the subclass: -# +# # - :meth:`init_path` # - :meth:`init_shell` (to be implemented by the subclass) # - :meth:`init_gui_pylab` @@ -37,13 +37,13 @@ "%alias status dist/status -e $$environment -p $$payout_id -rp $$redis_password -ru $$redis_username", "%alias authorize dist/authorize -e $$environment -p $$payout_id -k $$operator_key -ru $$redis_username -rp $$redis_password -pr $$payout_report -pcr2 $$pcr2 $$prepare_log", "%alias bootstrap dist/bootstrap -b $$secrets_s3_bucket -v -e $$environment -p $$operator_key -pcr2 $$pcr2 %s", -"%alias prepare dist/prepare -e $$environment -p $$payout_id -ru $$redis_username -rp $$redis_password -pcr2 $$pcr2 $$payout_report", +"%alias prepare dist/prepare -e $$environment -p $$payout_id -k $$operator_key -ru $$redis_username -rp $$redis_password -pcr2 $$pcr2 $$payout_report", "%alias report dist/report -e $$environment -p $$payout_id -ru $$redis_username -rp $$redis_password -pcr2 $$pcr2 $$payout_report", "%alias info dist/info -e $$environment -pcr2 $$pcr2 $$payout_report", "%alias await_prepare touch $$prepare_log && dist/prepare -cg cli2 -e $$environment -p $$payout_id -ru $$redis_username -rp $$redis_password -pcr2 $$pcr2 $$payout_report", -"%alias redis redis-cli -p 6380 --user $$redis_username --pass $$redis_password", -"%alias flush_redis redis-cli -p 6380 --user $$redis_username --pass $$redis_password del \*$$payout_id\*", -"%alias list_payouts redis-cli -p 6380 --user $$redis_username --pass $$redis_password keys \*", +"%alias redis redis-cli -p 6380 --user $$redis_username", +"%alias flush_redis redis-cli -p 6380 --user $$redis_username del \*$$payout_id\*", +"%alias list_payouts redis-cli -p 6380 --user $$redis_username keys \*", "%alias worker_logs AWS_VAULT= kubectl --context $$cluster --namespace payment-$$environment logs deployments/worker", "%alias enclave_logs AWS_VAULT= kubectl --context $$cluster --namespace payment-$$environment logs deployments/web -c nitro-utils", "%alias pods AWS_VAULT= kubectl --context $$cluster --namespace payment-$$environment get pods", @@ -58,9 +58,9 @@ # c.InteractiveShellApp.extensions = [] ## Dotted module name(s) of one or more IPython extensions to load. -# +# # For specifying extra extensions to load on the command-line. -# +# # .. versionadded:: 7.10 # Default: [] # c.InteractiveShellApp.extra_extensions = [] @@ -105,7 +105,7 @@ ## If true, IPython will populate the user namespace with numpy, pylab, etc. # and an ``import *`` is done from numpy and pylab, when using pylab mode. -# +# # When False, pylab mode should not import any names into the user # namespace. # Default: True @@ -134,32 +134,32 @@ # c.Application.log_level = 30 ## Configure additional log handlers. -# +# # The default stderr logs handler is configured by the log_level, log_datefmt # and log_format settings. -# +# # This configuration can be used to configure additional handlers (e.g. to # output the log to a file) or for finer control over the default handlers. -# +# # If provided this should be a logging configuration dictionary, for more # information see: # https://docs.python.org/3/library/logging.config.html#logging-config- # dictschema -# +# # This dictionary is merged with the base logging configuration which defines # the following: -# +# # * A logging formatter intended for interactive use called # ``console``. # * A logging handler that writes to stderr called # ``console`` which uses the formatter ``console``. # * A logger with the name of this application set to ``DEBUG`` # level. -# +# # This example adds a new handler that writes to a file: -# +# # .. code-block:: python -# +# # c.Application.logging_config = { # "handlers": { # "file": { @@ -206,7 +206,7 @@ # c.BaseIPythonApplication.copy_config_files = False ## Path to an extra config file to load. -# +# # If specified, load this config file in addition to any other IPython # config. # Default: '' @@ -231,7 +231,7 @@ # See also: Application.log_level # c.BaseIPythonApplication.log_level = 30 -## +## # See also: Application.logging_config # c.BaseIPythonApplication.logging_config = {} @@ -295,7 +295,7 @@ # See also: BaseIPythonApplication.extra_config_file # c.TerminalIPythonApp.extra_config_file = '' -## +## # See also: InteractiveShellApp.extra_extensions # c.TerminalIPythonApp.extra_extensions = [] @@ -328,7 +328,7 @@ # Default: 'IPython.terminal.interactiveshell.TerminalInteractiveShell' # c.TerminalIPythonApp.interactive_shell_class = 'IPython.terminal.interactiveshell.TerminalInteractiveShell' -## +## # See also: BaseIPythonApplication.ipython_dir # c.TerminalIPythonApp.ipython_dir = '' @@ -344,7 +344,7 @@ # See also: Application.log_level # c.TerminalIPythonApp.log_level = 30 -## +## # See also: Application.logging_config # c.TerminalIPythonApp.logging_config = {} @@ -554,11 +554,11 @@ #------------------------------------------------------------------------------ # TerminalInteractiveShell(InteractiveShell) configuration #------------------------------------------------------------------------------ -## +## # See also: InteractiveShell.ast_node_interactivity # c.TerminalInteractiveShell.ast_node_interactivity = 'last_expr' -## +## # See also: InteractiveShell.ast_transformers # c.TerminalInteractiveShell.ast_transformers = [] @@ -567,11 +567,11 @@ # Default: False # c.TerminalInteractiveShell.auto_match = False -## +## # See also: InteractiveShell.autoawait # c.TerminalInteractiveShell.autoawait = True -## +## # See also: InteractiveShell.autocall # c.TerminalInteractiveShell.autocall = 0 @@ -579,11 +579,11 @@ # Default: None # c.TerminalInteractiveShell.autoformatter = None -## +## # See also: InteractiveShell.autoindent # c.TerminalInteractiveShell.autoindent = True -## +## # See also: InteractiveShell.automagic # c.TerminalInteractiveShell.automagic = True @@ -602,11 +602,11 @@ # See also: InteractiveShell.banner2 # c.TerminalInteractiveShell.banner2 = '' -## +## # See also: InteractiveShell.cache_size # c.TerminalInteractiveShell.cache_size = 1000 -## +## # See also: InteractiveShell.color_info # c.TerminalInteractiveShell.color_info = True @@ -658,7 +658,7 @@ # Default: True # c.TerminalInteractiveShell.enable_history_search = True -## +## # See also: InteractiveShell.enable_html_pager # c.TerminalInteractiveShell.enable_html_pager = False @@ -690,7 +690,7 @@ # See also: InteractiveShell.history_length # c.TerminalInteractiveShell.history_length = 10000 -## +## # See also: InteractiveShell.history_load_length # c.TerminalInteractiveShell.history_load_length = 1000 @@ -701,15 +701,15 @@ # See also: InteractiveShell.ipython_dir # c.TerminalInteractiveShell.ipython_dir = '' -## +## # See also: InteractiveShell.logappend # c.TerminalInteractiveShell.logappend = '' -## +## # See also: InteractiveShell.logfile # c.TerminalInteractiveShell.logfile = '' -## +## # See also: InteractiveShell.logstart # c.TerminalInteractiveShell.logstart = False @@ -734,7 +734,7 @@ # See also: InteractiveShell.object_info_string_level # c.TerminalInteractiveShell.object_info_string_level = 0 -## +## # See also: InteractiveShell.pdb # c.TerminalInteractiveShell.pdb = False @@ -770,20 +770,20 @@ # c.TerminalInteractiveShell.separate_out2 = '' ## Add, disable or modifying shortcuts. -# +# # Each entry on the list should be a dictionary with ``command`` key # identifying the target function executed by the shortcut and at least # one of the following: -# +# # - ``match_keys``: list of keys used to match an existing shortcut, # - ``match_filter``: shortcut filter used to match an existing shortcut, # - ``new_keys``: list of keys to set, # - ``new_filter``: a new shortcut filter to set -# +# # The filters have to be composed of pre-defined verbs and joined by one # of the following conjunctions: ``&`` (and), ``|`` (or), ``~`` (not). # The pre-defined verbs are: -# +# # - `always` # - `never` # - `has_line_below` @@ -825,16 +825,16 @@ # - `navigable_suggestions` # - `cursor_in_leading_ws` # - `pass_through` -# +# # To disable a shortcut set ``new_keys`` to an empty list. # To add a shortcut add key ``create`` with value ``True``. -# +# # When modifying/disabling shortcuts, ``match_keys``/``match_filter`` can # be omitted if the provided specification uniquely identifies a shortcut # to be modified/disabled. When modifying a shortcut ``new_filter`` or # ``new_keys`` can be omitted which will result in reuse of the existing # filter/keys. -# +# # Only shortcuts defined in IPython (and not default prompt-toolkit # shortcuts) can be modified or disabled. The full list of shortcuts, # command identifiers and filters is available under @@ -847,10 +847,10 @@ # c.TerminalInteractiveShell.show_rewritten_input = True ## Use `raw_input` for the REPL, without completion and prompt colors. -# +# # Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are: # IPython own testing machinery, and emacs inferior-shell integration through elpy. -# +# # This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT` # environment variable is set, or the current terminal is not a tty. # Default: False @@ -863,7 +863,7 @@ # Default: 6 # c.TerminalInteractiveShell.space_for_menu = 6 -## +## # See also: InteractiveShell.sphinxify_docstring # c.TerminalInteractiveShell.sphinxify_docstring = False @@ -884,7 +884,7 @@ ## Use 24bit colors instead of 256 colors in prompt highlighting. # If your terminal supports true color, the following command should # print ``TRUECOLOR`` in orange:: -# +# # printf "\x1b[38;2;255;100;0mTRUECOLOR\x1b[0m\n" # Default: False # c.TerminalInteractiveShell.true_color = False @@ -910,19 +910,19 @@ # HistoryAccessor(HistoryAccessorBase) configuration #------------------------------------------------------------------------------ ## Access the history database without adding to it. -# +# # This is intended for use by standalone history tools. IPython shells use # HistoryManager, below, which is a subclass of this. ## Options for configuring the SQLite connection -# +# # These options are passed as keyword args to sqlite3.connect # when establishing database connections. # Default: {} # c.HistoryAccessor.connection_options = {} ## enable the SQLite history -# +# # set enabled=False to disable the SQLite history, # in which case there will be no stored history, no SQLite connection, # and no background saving thread. This may be necessary in some @@ -931,17 +931,17 @@ # c.HistoryAccessor.enabled = True ## Path to file to use for SQLite history database. -# +# # By default, IPython will put the history database in the IPython # profile directory. If you would rather share one history among # profiles, you can set this value in each, so that they are consistent. -# +# # Due to an issue with fcntl, SQLite is known to misbehave on some NFS # mounts. If you see IPython hanging, try setting this to something on a # local disk, e.g:: -# +# # ipython --HistoryManager.hist_file=/tmp/ipython_hist.sqlite -# +# # you can also use the specific value `:memory:` (including the colon # at both end but not the back ticks), to avoid creating an history file. # Default: traitlets.Undefined @@ -983,24 +983,24 @@ # c.MagicsManager.auto_magic = True ## Mapping from magic names to modules to load. -# +# # This can be used in IPython/IPykernel configuration to declare lazy magics # that will only be imported/registered on first use. -# +# # For example:: -# +# # c.MagicsManager.lazy_magics = { # "my_magic": "slow.to.import", # "my_other_magic": "also.slow", # } -# +# # On first invocation of `%my_magic`, `%%my_magic`, `%%my_other_magic` or # `%%my_other_magic`, the corresponding module will be loaded as an ipython # extensions as if you had previously done `%load_ext ipython`. -# +# # Magics names should be without percent(s) as magics can be both cell and line # magics. -# +# # Lazy loading happen relatively late in execution process, and complex # extensions that manipulate Python/IPython internal state or global state might # not support lazy loading. @@ -1011,10 +1011,10 @@ # ProfileDir(LoggingConfigurable) configuration #------------------------------------------------------------------------------ ## An object to manage the profile directory and its resources. -# +# # The profile directory is used by all IPython applications, to manage # configuration, logging and security. -# +# # This object knows how to find, create and manage these directories. This # should be used by any code that wants to handle profiles. @@ -1027,25 +1027,25 @@ # BaseFormatter(Configurable) configuration #------------------------------------------------------------------------------ ## A base formatter class that is configurable. -# +# # This formatter should usually be used as the base class of all formatters. # It is a traited :class:`Configurable` class and includes an extensible # API for users to determine how their objects are formatted. The following # logic is used to find a function to format an given object. -# +# # 1. The object is introspected to see if it has a method with the name # :attr:`print_method`. If is does, that object is passed to that method # for formatting. # 2. If no print method is found, three internal dictionaries are consulted # to find print method: :attr:`singleton_printers`, :attr:`type_printers` # and :attr:`deferred_printers`. -# +# # Users should use these dictionaries to register functions that will be # used to compute the format data for their objects (if those objects don't # have the special print methods). The easiest way of using these # dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name` # methods. -# +# # If no function/callable is found to compute the format data, ``None`` is # returned and this format type is not used. @@ -1065,12 +1065,12 @@ # PlainTextFormatter(BaseFormatter) configuration #------------------------------------------------------------------------------ ## The default pretty-printer. -# +# # This uses :mod:`IPython.lib.pretty` to compute the format data of # the object. If the object cannot be pretty printed, :func:`repr` is used. # See the documentation of :mod:`IPython.lib.pretty` for details on # how to write pretty printers. Here is a simple example:: -# +# # def dtype_pprinter(obj, p, cycle): # if cycle: # return p.text('dtype(...)') @@ -1093,7 +1093,7 @@ # c.PlainTextFormatter.float_precision = '' ## Truncate large collections (lists, dicts, tuples, sets) to this size. -# +# # Set to 0 to disable truncation. # Default: 1000 # c.PlainTextFormatter.max_seq_length = 1000 @@ -1120,7 +1120,7 @@ # Completer(Configurable) configuration #------------------------------------------------------------------------------ ## Enable auto-closing dictionary keys. -# +# # When enabled string keys will be suffixed with a final quote (matching the # opening quote), tuple keys will also receive a separating comma if needed, and # keys which are final will receive a closing bracket (``]``). @@ -1139,15 +1139,15 @@ # c.Completer.debug = False ## Policy for code evaluation under completion. -# +# # Successive options allow to enable more eager evaluation for better # completion suggestions, including for nested dictionaries, nested lists, # or even results of function calls. # Setting ``unsafe`` or higher can lead to evaluation of arbitrary user # code on :kbd:`Tab` with potentially unwanted or dangerous side effects. -# +# # Allowed values are: -# +# # - ``forbidden``: no evaluation of code is permitted, # - ``minimal``: evaluation of literals and access to built-in namespace; # no item/attribute evaluationm no access to locals/globals, @@ -1164,13 +1164,13 @@ # c.Completer.evaluation = 'limited' ## Activate greedy completion. -# +# # .. deprecated:: 8.8 # Use :std:configtrait:`Completer.evaluation` and :std:configtrait:`Completer.auto_close_dict_keys` instead. -# +# # When enabled in IPython 8.8 or newer, changes configuration as # follows: -# +# # - ``Completer.evaluation = 'unsafe'`` # - ``Completer.auto_close_dict_keys = True`` # Default: False @@ -1192,7 +1192,7 @@ #------------------------------------------------------------------------------ ## Extension of the completer class with IPython-specific features -## +## # See also: Completer.auto_close_dict_keys # c.IPCompleter.auto_close_dict_keys = False @@ -1208,7 +1208,7 @@ # c.IPCompleter.debug = False ## List of matchers to disable. -# +# # The list should contain matcher identifiers (see # :any:`completion_matcher`). # Default: [] @@ -1228,35 +1228,35 @@ # c.IPCompleter.jedi_compute_type_timeout = 400 ## DEPRECATED as of version 5.0. -# +# # Instruct the completer to use __all__ for the completion -# +# # Specifically, when completing on ``object.``. -# +# # When True: only those names in obj.__all__ will be included. -# +# # When False [default]: the __all__ attribute is ignored # Default: False # c.IPCompleter.limit_to__all__ = False ## Whether to merge completion results into a single list -# +# # If False, only the completion results from the first non-empty # completer will be returned. -# +# # As of version 8.6.0, setting the value to ``False`` is an alias for: # ``IPCompleter.suppress_competing_matchers = True.``. # Default: True # c.IPCompleter.merge_completions = True ## Instruct the completer to omit private method names -# +# # Specifically, when completing on ``object.``. -# +# # When 2 [default]: all names that start with '_' will be excluded. -# +# # When 1: all 'magic' names (``__foo__``) will be excluded. -# +# # When 0: nothing will be excluded. # Choices: any of [0, 1, 2] # Default: 2 @@ -1271,19 +1271,19 @@ # c.IPCompleter.profiler_output_dir = '.completion_profiles' ## Whether to suppress completions from other *Matchers*. -# +# # When set to ``None`` (default) the matchers will attempt to auto-detect # whether suppression of other matchers is desirable. For example, at the # beginning of a line followed by `%` we expect a magic completion to be the # only applicable option, and after ``my_dict['`` we usually expect a completion # with an existing dictionary key. -# +# # If you want to disable this heuristic and see completions from all matchers, # set ``IPCompleter.suppress_competing_matchers = False``. To disable the # heuristic for specific matchers provide a dictionary mapping: # ``IPCompleter.suppress_competing_matchers = {'IPCompleter.dict_key_matcher': # False}``. -# +# # Set ``IPCompleter.suppress_competing_matchers = True`` to limit completions to # the set of matchers with the highest priority; this is equivalent to # ``IPCompleter.merge_completions`` and can be beneficial for performance, but @@ -1301,22 +1301,22 @@ # ScriptMagics(Magics) configuration #------------------------------------------------------------------------------ ## Magics for talking to scripts -# +# # This defines a base `%%script` cell magic for running a cell # with a program in a subprocess, and registers a few top-level # magics that call %%script with common interpreters. ## Extra script cell magics to define -# +# # This generates simple wrappers of `%%script foo` as `%%foo`. -# +# # If you want to add script magics that aren't on your path, # specify them in script_paths # Default: [] # c.ScriptMagics.script_magics = [] ## Dict mapping short 'ruby' names to full paths, such as '/opt/secret/bin/ruby' -# +# # Only necessary for items in script_magics where the default path will not # find the right interpreter. # Default: {} @@ -1335,7 +1335,7 @@ # StoreMagics(Magics) configuration #------------------------------------------------------------------------------ ## Lightweight persistence for python variables. -# +# # Provides the %store magic. ## If True, any %store-d variables will be automatically restored diff --git a/tools/payments/ipython-profile/startup/00-setup.py b/tools/payments/ipython-profile/startup/00-setup.py index 0b9657520..8c0acaeff 100644 --- a/tools/payments/ipython-profile/startup/00-setup.py +++ b/tools/payments/ipython-profile/startup/00-setup.py @@ -26,6 +26,9 @@ environment = "dev" del aws_vault +if os.getenv("NITRO_ENCLAVE_MOCKING", ""): + environment = "local" + # FIXME TODO pull env vars and set during pcr verification secrets_s3_bucket = "" @@ -37,6 +40,12 @@ redis_password = os.getenv("REDIS_PASSWORD") operator_key = "~/.ssh/settlements" +os.putenv("REDISCLI_AUTH", redis_password) + +if os.getenv("NITRO_ENCLAVE_MOCKING", ""): + pcr2 = "0" * 96 + operator_key = "../../local-dev/secrets/payment-test-operator.pem" + jobs = bg.BackgroundJobManager() def _set_cluster(): @@ -75,6 +84,8 @@ def _set_redis_credentials(): def _get_web_env(): global redis_username, redis_password env = os.environ.copy() + if os.getenv("NITRO_ENCLAVE_MOCKING", ""): + return env if "AWS_VAULT" in env: del env["AWS_VAULT"] p = subprocess.Popen(["kubectl", "--context", cluster, "--namespace", f"payment-{environment}", "get", "deployments", "web", "-o", "json"], env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE) @@ -90,11 +101,15 @@ def _get_web_env(): return env def _set_secrets_s3_bucket(): - global secrets_s3_bucket + global secrets_s3_bucket + if os.getenv("NITRO_ENCLAVE_MOCKING", ""): + return env = _get_web_env() secrets_s3_bucket = env["ENCLAVE_CONFIG_BUCKET_NAME"] def _get_pcr2(): + if os.getenv("NITRO_ENCLAVE_MOCKING", ""): + return "0" * 96 env = os.environ.copy() web_env = _get_web_env() env["EIF_COMMAND"] = web_env["EIF_COMMAND"]