upload-source-maps.sh 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. #!/bin/sh
  2. # Sends the browser source maps of a finished `next build` to PostHog error
  3. # tracking, then deletes them. The Dockerfile runs it in the build stage, so an
  4. # exception on Torqvoice Cloud shows the file and line it came from instead of
  5. # a minified chunk.
  6. #
  7. # Off unless POSTHOG_SOURCEMAPS=on, which the image workflows set only when they
  8. # hold the upload key. Off, the build made no maps and there is nothing to do.
  9. #
  10. # An upload problem never fails the build. Without a key or a project, on a
  11. # platform with no pinned CLI, or when the upload goes wrong, it says so and the
  12. # image is built as before, only without readable stack traces.
  13. #
  14. # The maps themselves must never reach the image: self-hosted installs run the
  15. # same image, and anything in .next/static is served to whoever asks. If one is
  16. # still there at the end, the build fails.
  17. set -u
  18. STATIC_DIR=.next/static
  19. KEY_FILE=/run/secrets/posthog_cli_api_key
  20. RELEASE_NAME=torqvoice
  21. RELEASE_VERSION=${APP_VERSION:-development}
  22. PROJECT_ID=${POSTHOG_CLI_PROJECT_ID:-}
  23. HOST=${POSTHOG_CLI_HOST:-https://eu.posthog.com}
  24. # The CLI release to download and the SHA-256 of each archive. Bumping the
  25. # version means bumping both sums with it; each archive on the release page has
  26. # a .sha256 file beside it.
  27. CLI_VERSION=0.18.12
  28. CLI_SHA256_X86_64=4799c1e81318511885295dd22599c38aec99430559da570ff8f6c70473c257aa
  29. CLI_SHA256_AARCH64=1c9b8181c0bed920dfa5ce8388ac22e5418951f1a86ca95c10c4819f3feadfd8
  30. WORK_DIR=
  31. log() {
  32. echo "source maps: $*"
  33. }
  34. has_maps() {
  35. [ -n "$(find "$STATIC_DIR" -type f -name '*.map' | head -n 1)" ]
  36. }
  37. # Whatever happened above, no map leaves this stage. The comments pointing at
  38. # them go too, so a browser with dev tools open does not ask for missing files.
  39. finish() {
  40. [ -n "$WORK_DIR" ] && rm -rf "$WORK_DIR"
  41. if has_maps; then
  42. find "$STATIC_DIR" -type f -name '*.map' -exec rm -f {} +
  43. find "$STATIC_DIR" -type f -name '*.js' -exec sed -i '/^\/\/# sourceMappingURL=/d' {} +
  44. find "$STATIC_DIR" -type f -name '*.css' -exec sed -i 's|/\*# sourceMappingURL=[^*]*\*/||' {} +
  45. fi
  46. if has_maps; then
  47. log "could not delete the maps in $STATIC_DIR; refusing to build an image that serves them"
  48. exit 1
  49. fi
  50. exit 0
  51. }
  52. if [ "${POSTHOG_SOURCEMAPS:-off}" != "on" ]; then
  53. finish
  54. fi
  55. if [ ! -s "$KEY_FILE" ]; then
  56. log "no upload key, skipping"
  57. finish
  58. fi
  59. if [ -z "$PROJECT_ID" ]; then
  60. log "no PostHog project id (POSTHOG_CLI_PROJECT_ID), skipping"
  61. finish
  62. fi
  63. if ! has_maps; then
  64. log "the build made no maps in $STATIC_DIR, skipping"
  65. finish
  66. fi
  67. case "$(uname -m)" in
  68. x86_64) ARCH=x86_64 SUM=$CLI_SHA256_X86_64 ;;
  69. aarch64 | arm64) ARCH=aarch64 SUM=$CLI_SHA256_AARCH64 ;;
  70. *)
  71. log "no pinned posthog-cli for $(uname -m), skipping"
  72. finish
  73. ;;
  74. esac
  75. WORK_DIR=$(mktemp -d)
  76. ARCHIVE="$WORK_DIR/posthog-cli.tar.gz"
  77. URL="https://github.com/PostHog/posthog/releases/download/posthog-cli/v${CLI_VERSION}/posthog-cli-${ARCH}-unknown-linux-musl.tar.gz"
  78. if ! wget -q -O "$ARCHIVE" "$URL"; then
  79. log "could not download posthog-cli $CLI_VERSION, skipping"
  80. finish
  81. fi
  82. # A changed or tampered download is never run
  83. if ! echo "$SUM $ARCHIVE" | sha256sum -c - >/dev/null 2>&1; then
  84. log "the posthog-cli download does not match its pinned SHA-256, skipping"
  85. finish
  86. fi
  87. if ! tar -xzf "$ARCHIVE" -C "$WORK_DIR"; then
  88. log "could not unpack posthog-cli, skipping"
  89. finish
  90. fi
  91. CLI="$WORK_DIR/posthog-cli-${ARCH}-unknown-linux-musl/posthog-cli"
  92. # `process` stamps each chunk with the id its map is filed under, uploads the
  93. # maps, and with --delete-after removes them and their comments again. The
  94. # stamped chunks are what the image serves, so the browser reports those ids.
  95. log "uploading for $RELEASE_NAME $RELEASE_VERSION to project $PROJECT_ID"
  96. if POSTHOG_CLI_API_KEY="$(cat "$KEY_FILE")" \
  97. POSTHOG_CLI_PROJECT_ID="$PROJECT_ID" \
  98. POSTHOG_CLI_HOST="$HOST" \
  99. "$CLI" sourcemap process \
  100. --directory "$STATIC_DIR" \
  101. --release-name "$RELEASE_NAME" \
  102. --release-version "$RELEASE_VERSION" \
  103. --delete-after; then
  104. log "uploaded"
  105. else
  106. log "the upload failed; this image's stack traces stay minified"
  107. fi
  108. finish