GitProxy v{siteConfig.customFields.version} is out! 🥳
-
{siteConfig.tagline}
+
+
+ GitProxy deploys custom push protections and policies on top of Git. It is a highly
+ configurable framework allowing developers and organizations to enforce push
+ protections relevant to their developer workflow, security posture and risk appetite.
+
+
+ GitProxy is built with a developer-first mindset. By presenting simple-to-follow
+ remediation instructions in the CLI/Terminal, it minimises the friction of use and
+ adoption, and keeps developers focused on what matters: committing and pushing code.
+
+
diff --git a/website/static/demo/git-push-narrow.cast b/website/static/demo/git-push-narrow.cast
new file mode 100644
index 000000000..0a372f207
--- /dev/null
+++ b/website/static/demo/git-push-narrow.cast
@@ -0,0 +1,400 @@
+{"version": 2, "width": 60, "height": 34, "timestamp": 1793654124, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}}
+[0.010262, "o", "\u001b[H\u001b[2J\u001b[3J"]
+[0.010809, "o", "\u001b[1;32mdev@laptop\u001b[0m \u001b[1;34m~/payments-service\u001b[0m \u001b[33m(main)\u001b[0m $ "]
+[1.012869, "o", "\u001b[3;90m#"]
+[1.055103, "o", " "]
+[1.117401, "o", "A"]
+[1.15938, "o", " "]
+[1.221236, "o", "h"]
+[1.273242, "o", "a"]
+[1.335366, "o", "r"]
+[1.380017, "o", "d"]
+[1.442045, "o", "c"]
+[1.483919, "o", "o"]
+[1.515589, "o", "d"]
+[1.557978, "o", "e"]
+[1.619781, "o", "d"]
+[1.672134, "o", " "]
+[1.734555, "o", "A"]
+[1.786948, "o", "W"]
+[1.838642, "o", "S"]
+[1.870861, "o", " "]
+[1.933312, "o", "a"]
+[1.96514, "o", "c"]
+[2.007297, "o", "c"]
+[2.059579, "o", "e"]
+[2.092366, "o", "s"]
+[2.155248, "o", "s"]
+[2.187195, "o", " "]
+[2.249353, "o", "k"]
+[2.311273, "o", "e"]
+[2.34345, "o", "y"]
+[2.405798, "o", " "]
+[2.468423, "o", "s"]
+[2.52048, "o", "l"]
+[2.562726, "o", "i"]
+[2.615113, "o", "p"]
+[2.667673, "o", "s"]
+[2.710108, "o", " "]
+[2.77243, "o", "i"]
+[2.834505, "o", "n"]
+[2.866983, "o", "t"]
+[2.929189, "o", "o"]
+[2.971065, "o", " "]
+[3.033202, "o", "a"]
+[3.075347, "o", " "]
+[3.137674, "o", "c"]
+[3.17978, "o", "o"]
+[3.242113, "o", "m"]
+[3.274141, "o", "m"]
+[3.326, "o", "i"]
+[3.38832, "o", "t"]
+[3.451053, "o", "."]
+[3.483111, "o", "."]
+[3.536015, "o", "."]
+[3.568582, "o", "\u001b[0m"]
+[4.270786, "o", "\r\n\u001b[1;32mdev@laptop\u001b[0m \u001b[1;34m~/payments-service\u001b[0m \u001b[33m(main)\u001b[0m $ "]
+[4.87276, "o", "c"]
+[4.924433, "o", "a"]
+[4.966236, "o", "t"]
+[5.008205, "o", " "]
+[5.070336, "o", "s"]
+[5.133055, "o", "r"]
+[5.195545, "o", "c"]
+[5.257495, "o", "/"]
+[5.30016, "o", "s"]
+[5.34247, "o", "3"]
+[5.394972, "o", "."]
+[5.457668, "o", "t"]
+[5.510114, "o", "s"]
+[5.924095, "o", "\r\n"]
+[5.926175, "o", "import { S3Client } from '@aws-sdk/client-s3';\r\n\r\nexport const s3 = new S3Client({\r\n region: 'us-east-1',\r\n credentials: {\r\n accessKeyId: 'AKIAIOSFODNN7EXAMPLE',\r\n secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,\r\n },\r\n});\r\n"]
+[5.926484, "o", "\u001b[1;32mdev@laptop\u001b[0m \u001b[1;34m~/payments-service\u001b[0m \u001b[33m(main)\u001b[0m $ "]
+[7.428834, "o", "g"]
+[7.481056, "o", "i"]
+[7.543276, "o", "t"]
+[7.595477, "o", " "]
+[7.657584, "o", "a"]
+[7.709516, "o", "d"]
+[7.75122, "o", "d"]
+[7.79321, "o", " "]
+[7.855185, "o", "s"]
+[7.896953, "o", "r"]
+[7.929072, "o", "c"]
+[7.991477, "o", "/"]
+[8.034171, "o", "s"]
+[8.096529, "o", "3"]
+[8.148634, "o", "."]
+[8.180586, "o", "t"]
+[8.222613, "o", "s"]
+[8.254403, "o", " "]
+[8.316314, "o", "&"]
+[8.37828, "o", "&"]
+[8.42087, "o", " "]
+[8.483571, "o", "g"]
+[8.545591, "o", "i"]
+[8.577952, "o", "t"]
+[8.620373, "o", " "]
+[8.682116, "o", "c"]
+[8.714081, "o", "o"]
+[8.756207, "o", "m"]
+[8.788264, "o", "m"]
+[8.820133, "o", "i"]
+[8.88216, "o", "t"]
+[8.934036, "o", " "]
+[8.995929, "o", "-"]
+[9.049082, "o", "q"]
+[9.08121, "o", " "]
+[9.14325, "o", "-"]
+[9.185232, "o", "m"]
+[9.227113, "o", " "]
+[9.288963, "o", "'"]
+[9.35094, "o", "A"]
+[9.383092, "o", "d"]
+[9.445634, "o", "d"]
+[9.488074, "o", " "]
+[9.550247, "o", "S"]
+[9.602357, "o", "3"]
+[9.654319, "o", " "]
+[9.71684, "o", "c"]
+[9.759684, "o", "l"]
+[9.791594, "o", "i"]
+[9.844027, "o", "e"]
+[9.896234, "o", "n"]
+[9.948576, "o", "t"]
+[10.00016, "o", " "]
+[10.062532, "o", "f"]
+[10.094314, "o", "o"]
+[10.15637, "o", "r"]
+[10.188486, "o", " "]
+[10.25064, "o", "r"]
+[10.282747, "o", "e"]
+[10.345025, "o", "p"]
+[10.396788, "o", "o"]
+[10.428948, "o", "r"]
+[10.490984, "o", "t"]
+[10.522806, "o", " "]
+[10.585071, "o", "u"]
+[10.647374, "o", "p"]
+[10.699268, "o", "l"]
+[10.741219, "o", "o"]
+[10.783006, "o", "a"]
+[10.835056, "o", "d"]
+[10.896838, "o", "s"]
+[10.949189, "o", "'"]
+[11.33304, "o", "\r\n"]
+[11.342285, "o", "\u001b[1;32mdev@laptop\u001b[0m \u001b[1;34m~/payments-service\u001b[0m \u001b[33m(main)\u001b[0m $ "]
+[12.343942, "o", "g"]
+[12.405941, "o", "i"]
+[12.458367, "o", "t"]
+[12.520924, "o", " "]
+[12.582945, "o", "p"]
+[12.645266, "o", "u"]
+[12.677297, "o", "s"]
+[12.73962, "o", "h"]
+[13.143958, "o", "\r\n"]
+[13.181226, "o", "Enumerating objects: 6, done.\r\nCounting objects: 16% (1/6)\r"]
+[13.181455, "o", "Counting objects: 33% (2/6)\rCounting objects: 50% (3/6)\rCounting objects: 66% (4/6)\rCounting objects: 83% (5/6)\rCounting objects: 100% (6/6)\rCounting objects: 100% (6/6), done.\r\nDelta compression using up to 2 threads\r\nCompressing objects: 25% (1/4)\rCompressing objects: 50% (2/4)\rCompressing objects: 75% (3/4)\r"]
+[13.182167, "o", "Compressing objects: 100% (4/4)\rCompressing objects: 100% (4/4), done.\r\n"]
+[13.182323, "o", "Writing objects: 25% (1/4)\rWriting objects: 50% (2/4)\rWriting objects: 75% (3/4)\rWriting objects: 100% (4/4)\rWriting objects: 100% (4/4), 551 bytes | 551.00 KiB/s, done.\r\nTotal 4 (delta 0), reused 0 (delta 0), pack-reused 0\r\n"]
+[13.215897, "o", "remote: Resolving user from token...\u001b[K\r\n"]
+[13.216266, "o", "remote: Checking for empty branch...\u001b[K\r\nremote: Checking repository is authorised...\u001b[K\r\n"]
+[13.21682, "o", "remote: Checking commit messages...\u001b[K\r\nremote: Checking author emails...\u001b[K\r\nremote: Checking push permissions...\u001b[K\r\n"]
+[13.21733, "o", "remote: Fetching remote repository...\u001b[K\r\n"]
+[13.305027, "o", "remote: Writing pack data...\u001b[K\r\nremote: Checking for hidden commits...\u001b[K\r\nremote: Checking approval status...\u001b[K\r\n"]
+[13.308909, "o", "remote: Running pre-receive hook...\u001b[K\r\nremote: Computing diff...\u001b[K\r\n"]
+[13.316172, "o", "remote: Scanning for secrets...\u001b[K\r\n"]
+[13.316364, "o", "remote: Scanning diff contents...\u001b[K\r\n"]
+[13.32029, "o", "remote: \t\u001b[K\r\nremote: \r\nremote: \r\nremote: "]
+[13.320482, "o", "\r\nremote: Your push has been blocked.\u001b[K\r\nremote: \r\nremote: Please ensure your code does not contain sensitive information or URLs.\u001b[K\r\nremote: \r\nremote: \r\nremote: ---------------------------------- #1 AWS Access Key ID ------------------------------\u001b[K\r\nremote: Policy Exception Type: AWS Access Key ID\u001b[K\r\nremote: DETECTED: AKIAIOSFODNN7EXAMPLE \u001b[K\r\nremote: FILE(S) LOCATED: src/s3.ts\u001b[K\r\nremote: Line(s) of code: 6\u001b[K\r\nremote: \r\nremote: \r\n"]
+[13.321342, "o", "To http://localhost:8000/github.com/my-org/payments-service.git\r\n \u001b[31m! [remote rejected]\u001b[m main -> main (rejected by GitProxy)\r\n\u001b[31merror: failed to push some refs to 'http://localhost:8000/github.com/my-org/payments-service.git'\r\n\u001b[m"]
+[13.322276, "o", "\u001b[1;32mdev@laptop\u001b[0m \u001b[1;34m~/payments-service\u001b[0m \u001b[33m(main)\u001b[0m $ "]
+[18.324216, "o", "c"]
+[18.356245, "o", "l"]
+[18.408257, "o", "e"]
+[18.450527, "o", "a"]
+[18.482348, "o", "r"]
+[18.886067, "o", "\r\n"]
+[18.887846, "o", "\u001b[H\u001b[2J\u001b[3J"]
+[18.888008, "o", "\u001b[1;32mdev@laptop\u001b[0m \u001b[1;34m~/payments-service\u001b[0m \u001b[33m(main)\u001b[0m $ "]
+[19.690175, "o", "\u001b[3;90m#"]
+[19.741846, "o", " "]
+[19.803638, "o", "R"]
+[19.835576, "o", "e"]
+[19.887746, "o", "a"]
+[19.949965, "o", "d"]
+[19.982071, "o", " "]
+[20.044054, "o", "t"]
+[20.076357, "o", "h"]
+[20.10874, "o", "e"]
+[20.150442, "o", " "]
+[20.212364, "o", "k"]
+[20.25441, "o", "e"]
+[20.296416, "o", "y"]
+[20.348443, "o", " "]
+[20.410224, "o", "f"]
+[20.452323, "o", "r"]
+[20.484098, "o", "o"]
+[20.516048, "o", "m"]
+[20.558175, "o", " "]
+[20.620573, "o", "t"]
+[20.652606, "o", "h"]
+[20.694532, "o", "e"]
+[20.75734, "o", " "]
+[20.819559, "o", "e"]
+[20.852335, "o", "n"]
+[20.904343, "o", "v"]
+[20.96609, "o", "i"]
+[21.018177, "o", "r"]
+[21.080585, "o", "o"]
+[21.143132, "o", "n"]
+[21.175675, "o", "m"]
+[21.218216, "o", "e"]
+[21.250451, "o", "n"]
+[21.292802, "o", "t"]
+[21.344932, "o", " "]
+[21.407043, "o", "i"]
+[21.46932, "o", "n"]
+[21.501411, "o", "s"]
+[21.543663, "o", "t"]
+[21.596088, "o", "e"]
+[21.638288, "o", "a"]
+[21.681152, "o", "d"]
+[21.733656, "o", ","]
+[21.78589, "o", " "]
+[21.848358, "o", "t"]
+[21.910239, "o", "h"]
+[21.941948, "o", "e"]
+[21.973835, "o", "n"]
+[22.035564, "o", " "]
+[22.09847, "o", "p"]
+[22.160186, "o", "u"]
+[22.202332, "o", "s"]
+[22.254412, "o", "h"]
+[22.296584, "o", " "]
+[22.358759, "o", "a"]
+[22.420984, "o", "g"]
+[22.473189, "o", "a"]
+[22.505435, "o", "i"]
+[22.567603, "o", "n"]
+[22.609962, "o", "\u001b[0m"]
+[23.312534, "o", "\r\n\u001b[1;32mdev@laptop\u001b[0m \u001b[1;34m~/payments-service\u001b[0m \u001b[33m(main)\u001b[0m $ "]
+[23.915029, "o", "s"]
+[23.977791, "o", "e"]
+[24.019949, "o", "d"]
+[24.062067, "o", " "]
+[24.124828, "o", "-"]
+[24.18707, "o", "i"]
+[24.22919, "o", " "]
+[24.292024, "o", "\""]
+[24.344297, "o", "s"]
+[24.40682, "o", "/"]
+[24.469368, "o", "'"]
+[24.532092, "o", "A"]
+[24.574807, "o", "K"]
+[24.616772, "o", "I"]
+[24.658932, "o", "A"]
+[24.700992, "o", "["]
+[24.732893, "o", "A"]
+[24.784796, "o", "-"]
+[24.846598, "o", "Z"]
+[24.878623, "o", "0"]
+[24.93061, "o", "-"]
+[24.982667, "o", "9"]
+[25.044755, "o", "]"]
+[25.107326, "o", "*"]
+[25.139562, "o", "'"]
+[25.171767, "o", "/"]
+[25.234149, "o", "p"]
+[25.286206, "o", "r"]
+[25.348819, "o", "o"]
+[25.380826, "o", "c"]
+[25.412455, "o", "e"]
+[25.44476, "o", "s"]
+[25.497086, "o", "s"]
+[25.529449, "o", "."]
+[25.571637, "o", "e"]
+[25.613572, "o", "n"]
+[25.665903, "o", "v"]
+[25.708417, "o", "."]
+[25.760977, "o", "A"]
+[25.803825, "o", "W"]
+[25.856258, "o", "S"]
+[25.908956, "o", "_"]
+[25.941821, "o", "A"]
+[26.003908, "o", "C"]
+[26.055734, "o", "C"]
+[26.118031, "o", "E"]
+[26.160022, "o", "S"]
+[26.201731, "o", "S"]
+[26.243931, "o", "_"]
+[26.276266, "o", "K"]
+[26.32844, "o", "E"]
+[26.390412, "o", "Y"]
+[26.452672, "o", "_"]
+[26.494813, "o", "I"]
+[26.537063, "o", "D"]
+[26.599257, "o", "!"]
+[26.661569, "o", "/"]
+[26.714022, "o", "\""]
+[26.766083, "o", " "]
+[26.828327, "o", "s"]
+[26.890726, "o", "r"]
+[26.932522, "o", "c"]
+[26.974533, "o", "/"]
+[27.02641, "o", "s"]
+[27.088973, "o", "3"]
+[27.131402, "o", "."]
+[27.194015, "o", "t"]
+[27.255883, "o", "s"]
+[27.660973, "o", "\r\n"]
+[27.663435, "o", "\u001b[1;32mdev@laptop\u001b[0m \u001b[1;34m~/payments-service\u001b[0m \u001b[33m(main)\u001b[0m $ "]
+[28.265726, "o", "g"]
+[28.298017, "o", "i"]
+[28.330752, "o", "t"]
+[28.363104, "o", " "]
+[28.424996, "o", "d"]
+[28.486991, "o", "i"]
+[28.549001, "o", "f"]
+[28.590848, "o", "f"]
+[29.004658, "o", "\r\n"]
+[29.006896, "o", "\u001b[1mdiff --git a/src/s3.ts b/src/s3.ts\u001b[m\r\n\u001b[1mindex 9f08ca1..45ac067 100644\u001b[m\r\n\u001b[1m--- a/src/s3.ts\u001b[m\r\n\u001b[1m+++ b/src/s3.ts\u001b[m\r\n\u001b[36m@@ -3,7 +3,7 @@\u001b[m \u001b[mimport { S3Client } from '@aws-sdk/client-s3';\u001b[m\r\n export const s3 = new S3Client({\u001b[m\r\n region: 'us-east-1',\u001b[m\r\n credentials: {\u001b[m\r\n\u001b[31m- accessKeyId: 'AKIAIOSFODNN7EXAMPLE',\u001b[m\r\n\u001b[32m+\u001b[m\u001b[32m accessKeyId: process.env.AWS_ACCESS_KEY_ID!,\u001b[m\r\n secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,\u001b[m\r\n },\u001b[m\r\n });\u001b[m\r\n"]
+[29.007097, "o", "\u001b[1;32mdev@laptop\u001b[0m \u001b[1;34m~/payments-service\u001b[0m \u001b[33m(main)\u001b[0m $ "]
+[31.509514, "o", "g"]
+[31.541335, "o", "i"]
+[31.593586, "o", "t"]
+[31.625677, "o", " "]
+[31.687726, "o", "c"]
+[31.739825, "o", "o"]
+[31.792167, "o", "m"]
+[31.854645, "o", "m"]
+[31.906652, "o", "i"]
+[31.958664, "o", "t"]
+[32.010462, "o", " "]
+[32.072569, "o", "-"]
+[32.134791, "o", "q"]
+[32.196998, "o", " "]
+[32.259097, "o", "-"]
+[32.321624, "o", "a"]
+[32.373842, "o", " "]
+[32.436588, "o", "-"]
+[32.49885, "o", "-"]
+[32.55077, "o", "a"]
+[32.612484, "o", "m"]
+[32.664334, "o", "e"]
+[32.706746, "o", "n"]
+[32.738987, "o", "d"]
+[32.791437, "o", " "]
+[32.853444, "o", "-"]
+[32.915367, "o", "-"]
+[32.957868, "o", "n"]
+[33.020019, "o", "o"]
+[33.082285, "o", "-"]
+[33.134617, "o", "e"]
+[33.167056, "o", "d"]
+[33.219114, "o", "i"]
+[33.261052, "o", "t"]
+[33.64492, "o", "\r\n"]
+[33.650932, "o", "\u001b[1;32mdev@laptop\u001b[0m \u001b[1;34m~/payments-service\u001b[0m \u001b[33m(main)\u001b[0m $ "]
+[34.653493, "o", "g"]
+[34.706077, "o", "i"]
+[34.768, "o", "t"]
+[34.830075, "o", " "]
+[34.892846, "o", "p"]
+[34.944736, "o", "u"]
+[35.007062, "o", "s"]
+[35.048933, "o", "h"]
+[35.463454, "o", "\r\n"]
+[35.510134, "o", "Enumerating objects: 6, done.\r\nCounting objects: 16% (1/6)\rCounting objects: 33% (2/6)\rCounting objects: 50% (3/6)\r"]
+[35.510331, "o", "Counting objects: 66% (4/6)\rCounting objects: 83% (5/6)\rCounting objects: 100% (6/6)\rCounting objects: 100% (6/6), done.\r\nDelta compression using up to 2 threads\r\nCompressing objects: 25% (1/4)\rCompressing objects: 50% (2/4)\r"]
+[35.510424, "o", "Compressing objects: 75% (3/4)\r"]
+[35.510568, "o", "Compressing objects: 100% (4/4)\r"]
+[35.510805, "o", "Compressing objects: 100% (4/4), done.\r\n"]
+[35.510998, "o", "Writing objects: 25% (1/4)\r"]
+[35.511151, "o", "Writing objects: 50% (2/4)\rWriting objects: 75% (3/4)\rWriting objects: 100% (4/4)\rWriting objects: 100% (4/4), 537 bytes | 537.00 KiB/s, done.\r\nTotal 4 (delta 0), reused 0 (delta 0), pack-reused 0\r\n"]
+[35.560042, "o", "remote: Resolving user from token...\u001b[K\r\n"]
+[35.560195, "o", "remote: Checking for empty branch...\u001b[K\r\nremote: Checking repository is authorised...\u001b[K\r\n"]
+[35.560316, "o", "remote: Checking commit messages...\u001b[K\r\n"]
+[35.560369, "o", "remote: Checking author emails...\u001b[K\r\nremote: Checking push permissions...\u001b[K\r\n"]
+[35.560556, "o", "remote: Fetching remote repository...\u001b[K\r\n"]
+[35.651515, "o", "remote: Writing pack data...\u001b[K\r\n"]
+[35.651866, "o", "remote: Checking for hidden commits...\u001b[K\r\n"]
+[35.65203, "o", "remote: Checking approval status...\u001b[K\r\n"]
+[35.656862, "o", "remote: Running pre-receive hook...\u001b[K\r\nremote: Computing diff...\u001b[K\r\n"]
+[35.663024, "o", "remote: Scanning for secrets...\u001b[K\r\nremote: Scanning diff contents...\u001b[K\r\nremote: Requesting approval...\u001b[K\r\n"]
+[35.66374, "o", "remote: \t\u001b[K\r\n"]
+[35.663773, "o", "remote: \r\n"]
+[35.663799, "o", "remote: \r\n"]
+[35.663911, "o", "remote: \u001b[32mGitProxy has received your push ✅\u001b[0m\u001b[K\r\nremote: \r\nremote: 🔗 Shareable Link\u001b[K\r\nremote: \r\nremote: \u001b[34mhttp://localhost:8080/dashboard/push/ade8b51c1c15d8926b205bff7b63105f5aeb86765a34c6d420c5be9e01c1b8f1\u001b[0m\u001b[K\r\nremote: \r\nremote: \r\nremote: \r\n"]
+[35.664521, "o", "To http://localhost:8000/github.com/my-org/payments-service.git\r\n"]
+[35.664644, "o", " \u001b[31m! [remote rejected]\u001b[m "]
+[35.664789, "o", "main -> main"]
+[35.664861, "o", " ("]
+[35.664924, "o", "approval required"]
+[35.664986, "o", ")"]
+[35.665049, "o", "\r\n"]
+[35.665123, "o", "\u001b[31m"]
+[35.66518, "o", "error: failed to push some refs to 'http://localhost:8000/github.com/my-org/payments-service.git'\r\n"]
+[35.665595, "o", "\u001b[m"]
+[35.66603, "o", "\u001b[1;32mdev@laptop\u001b[0m \u001b[1;34m~/payments-service\u001b[0m \u001b[33m(main)\u001b[0m $ "]
+[41.66823, "o", "\u001b[?25h"]
diff --git a/website/static/demo/git-push.cast b/website/static/demo/git-push.cast
new file mode 100644
index 000000000..2549f4f5b
--- /dev/null
+++ b/website/static/demo/git-push.cast
@@ -0,0 +1,402 @@
+{"version": 2, "width": 110, "height": 30, "timestamp": 1793654082, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}}
+[0.010127, "o", "\u001b[H\u001b[2J\u001b[3J"]
+[0.010573, "o", "\u001b[1;32mdev@laptop\u001b[0m \u001b[1;34m~/payments-service\u001b[0m \u001b[33m(main)\u001b[0m $ "]
+[1.012004, "o", "\u001b[3;90m#"]
+[1.053742, "o", " "]
+[1.115923, "o", "A"]
+[1.178046, "o", " "]
+[1.239903, "o", "h"]
+[1.301847, "o", "a"]
+[1.33366, "o", "r"]
+[1.385738, "o", "d"]
+[1.428532, "o", "c"]
+[1.470375, "o", "o"]
+[1.53259, "o", "d"]
+[1.594468, "o", "e"]
+[1.626697, "o", "d"]
+[1.659557, "o", " "]
+[1.722256, "o", "A"]
+[1.754586, "o", "W"]
+[1.786661, "o", "S"]
+[1.839056, "o", " "]
+[1.901857, "o", "a"]
+[1.934316, "o", "c"]
+[1.986805, "o", "c"]
+[2.038965, "o", "e"]
+[2.070976, "o", "s"]
+[2.103055, "o", "s"]
+[2.145534, "o", " "]
+[2.207987, "o", "k"]
+[2.260152, "o", "e"]
+[2.313369, "o", "y"]
+[2.365593, "o", " "]
+[2.428262, "o", "s"]
+[2.490618, "o", "l"]
+[2.542589, "o", "i"]
+[2.605359, "o", "p"]
+[2.637897, "o", "s"]
+[2.690644, "o", " "]
+[2.752931, "o", "i"]
+[2.80535, "o", "n"]
+[2.8676, "o", "t"]
+[2.909951, "o", "o"]
+[2.971999, "o", " "]
+[3.034328, "o", "a"]
+[3.096509, "o", " "]
+[3.15883, "o", "c"]
+[3.221004, "o", "o"]
+[3.263485, "o", "m"]
+[3.315517, "o", "m"]
+[3.377651, "o", "i"]
+[3.409777, "o", "t"]
+[3.441809, "o", "."]
+[3.474073, "o", "."]
+[3.536483, "o", "."]
+[3.58877, "o", "\u001b[0m"]
+[4.291014, "o", "\r\n\u001b[1;32mdev@laptop\u001b[0m \u001b[1;34m~/payments-service\u001b[0m \u001b[33m(main)\u001b[0m $ "]
+[4.893308, "o", "c"]
+[4.955567, "o", "a"]
+[4.987834, "o", "t"]
+[5.019915, "o", " "]
+[5.082076, "o", "s"]
+[5.134071, "o", "r"]
+[5.196175, "o", "c"]
+[5.258528, "o", "/"]
+[5.301684, "o", "s"]
+[5.334122, "o", "3"]
+[5.366348, "o", "."]
+[5.418972, "o", "t"]
+[5.471625, "o", "s"]
+[5.876497, "o", "\r\n"]
+[5.87822, "o", "import { S3Client } from '@aws-sdk/client-s3';\r\n\r\nexport const s3 = new S3Client({\r\n region: 'us-east-1',\r\n credentials: {\r\n accessKeyId: 'AKIAIOSFODNN7EXAMPLE',\r\n secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,\r\n },\r\n});\r\n"]
+[5.878599, "o", "\u001b[1;32mdev@laptop\u001b[0m \u001b[1;34m~/payments-service\u001b[0m \u001b[33m(main)\u001b[0m $ "]
+[7.380453, "o", "g"]
+[7.423126, "o", "i"]
+[7.485422, "o", "t"]
+[7.527248, "o", " "]
+[7.589533, "o", "a"]
+[7.64215, "o", "d"]
+[7.684217, "o", "d"]
+[7.717052, "o", " "]
+[7.779122, "o", "s"]
+[7.811357, "o", "r"]
+[7.843405, "o", "c"]
+[7.905916, "o", "/"]
+[7.958051, "o", "s"]
+[7.989915, "o", "3"]
+[8.022583, "o", "."]
+[8.065066, "o", "t"]
+[8.107268, "o", "s"]
+[8.139455, "o", " "]
+[8.201609, "o", "&"]
+[8.23361, "o", "&"]
+[8.296089, "o", " "]
+[8.358805, "o", "g"]
+[8.401425, "o", "i"]
+[8.433944, "o", "t"]
+[8.476583, "o", " "]
+[8.538716, "o", "c"]
+[8.581361, "o", "o"]
+[8.613903, "o", "m"]
+[8.676486, "o", "m"]
+[8.708336, "o", "i"]
+[8.760555, "o", "t"]
+[8.812375, "o", " "]
+[8.874617, "o", "-"]
+[8.907002, "o", "q"]
+[8.939305, "o", " "]
+[9.001379, "o", "-"]
+[9.053651, "o", "m"]
+[9.096262, "o", " "]
+[9.158482, "o", "'"]
+[9.191124, "o", "A"]
+[9.253162, "o", "d"]
+[9.298487, "o", "d"]
+[9.359602, "o", " "]
+[9.422106, "o", "S"]
+[9.464227, "o", "3"]
+[9.526798, "o", " "]
+[9.589391, "o", "c"]
+[9.651623, "o", "l"]
+[9.714252, "o", "i"]
+[9.766867, "o", "e"]
+[9.819554, "o", "n"]
+[9.863845, "o", "t"]
+[9.906427, "o", " "]
+[9.968768, "o", "f"]
+[10.021448, "o", "o"]
+[10.053931, "o", "r"]
+[10.116, "o", " "]
+[10.17821, "o", "r"]
+[10.230374, "o", "e"]
+[10.273116, "o", "p"]
+[10.315375, "o", "o"]
+[10.357737, "o", "r"]
+[10.399528, "o", "t"]
+[10.451708, "o", " "]
+[10.514091, "o", "u"]
+[10.556344, "o", "p"]
+[10.588195, "o", "l"]
+[10.640343, "o", "o"]
+[10.692137, "o", "a"]
+[10.755077, "o", "d"]
+[10.797558, "o", "s"]
+[10.829355, "o", "'"]
+[11.24337, "o", "\r\n"]
+[11.252588, "o", "\u001b[1;32mdev@laptop\u001b[0m \u001b[1;34m~/payments-service\u001b[0m \u001b[33m(main)\u001b[0m $ "]
+[12.254785, "o", "g"]
+[12.307162, "o", "i"]
+[12.339585, "o", "t"]
+[12.391533, "o", " "]
+[12.45398, "o", "p"]
+[12.506354, "o", "u"]
+[12.569007, "o", "s"]
+[12.611195, "o", "h"]
+[13.025392, "o", "\r\n"]
+[13.072099, "o", "Enumerating objects: 6, done.\r\n"]
+[13.072322, "o", "Counting objects: 16% (1/6)\rCounting objects: 33% (2/6)\rCounting objects: 50% (3/6)\rCounting objects: 66% (4/6)\rCounting objects: 83% (5/6)\rCounting objects: 100% (6/6)\rCounting objects: 100% (6/6), done.\r\nDelta compression using up to 2 threads\r\n"]
+[13.072616, "o", "Compressing objects: 25% (1/4)\rCompressing objects: 50% (2/4)\rCompressing objects: 75% (3/4)\r"]
+[13.073363, "o", "Compressing objects: 100% (4/4)\r"]
+[13.07357, "o", "Compressing objects: 100% (4/4), done.\r\nWriting objects: 25% (1/4)\rWriting objects: 50% (2/4)\rWriting objects: 75% (3/4)\rWriting objects: 100% (4/4)\rWriting objects: 100% (4/4), 554 bytes | 554.00 KiB/s, done.\r\nTotal 4 (delta 0), reused 0 (delta 0), pack-reused 0\r\n"]
+[13.107051, "o", "remote: Resolving user from token...\u001b[K\r\n"]
+[13.107364, "o", "remote: Checking for empty branch...\u001b[K\r\nremote: Checking repository is authorised...\u001b[K\r\n"]
+[13.107894, "o", "remote: Checking commit messages...\u001b[K\r\n"]
+[13.107981, "o", "remote: Checking author emails...\u001b[K\r\nremote: Checking push permissions...\u001b[K\r\n"]
+[13.10836, "o", "remote: Fetching remote repository...\u001b[K\r\n"]
+[13.187708, "o", "remote: Writing pack data...\u001b[K\r\nremote: Checking for hidden commits...\u001b[K\r\nremote: Checking approval status...\u001b[K\r\n"]
+[13.189759, "o", "remote: Running pre-receive hook...\u001b[K\r\nremote: Computing diff...\u001b[K\r\n"]
+[13.195085, "o", "remote: Scanning for secrets...\u001b[K\r\nremote: Scanning diff contents...\u001b[K\r\n"]
+[13.19572, "o", "remote: \t\u001b[K\r\nremote: \r\nremote: \r\nremote: \r\nremote: Your push has been blocked.\u001b[K\r\nremote: \r\nremote: Please ensure your code does not contain sensitive information or URLs.\u001b[K\r\nremote: \r\nremote: \r\nremote: ---------------------------------- #1 AWS Access Key ID ------------------------------\u001b[K\r\nremote: Policy Exception Type: AWS Access Key ID\u001b[K\r\nremote: DETECTED: AKIAIOSFODNN7EXAMPLE \u001b[K\r\nremote: FILE(S) LOCATED: src/s3.ts\u001b[K\r\nremote: Line(s) of code: 6\u001b[K\r\nremote: \r\nremote: \r\n"]
+[13.196244, "o", "To http://localhost:8000/github.com/my-org/payments-service.git\r\n"]
+[13.196343, "o", " \u001b[31m! [remote rejected]\u001b[m main -> main (rejected by GitProxy)\r\n\u001b[31merror: failed to push some refs to 'http://localhost:8000/github.com/my-org/payments-service.git'\r\n\u001b[m"]
+[13.1976, "o", "\u001b[1;32mdev@laptop\u001b[0m \u001b[1;34m~/payments-service\u001b[0m \u001b[33m(main)\u001b[0m $ "]
+[18.199953, "o", "c"]
+[18.243094, "o", "l"]
+[18.296334, "o", "e"]
+[18.359401, "o", "a"]
+[18.402019, "o", "r"]
+[18.796301, "o", "\r\n"]
+[18.798321, "o", "\u001b[H\u001b[2J\u001b[3J"]
+[18.798489, "o", "\u001b[1;32mdev@laptop\u001b[0m \u001b[1;34m~/payments-service\u001b[0m \u001b[33m(main)\u001b[0m $ "]
+[19.602428, "o", "\u001b[3;90m"]
+[19.602587, "o", "#"]
+[19.645888, "o", " "]
+[19.707835, "o", "R"]
+[19.739695, "o", "e"]
+[19.781843, "o", "a"]
+[19.843731, "o", "d"]
+[19.905746, "o", " "]
+[19.968095, "o", "t"]
+[20.020182, "o", "h"]
+[20.081967, "o", "e"]
+[20.124002, "o", " "]
+[20.186428, "o", "k"]
+[20.238228, "o", "e"]
+[20.290484, "o", "y"]
+[20.332406, "o", " "]
+[20.39466, "o", "f"]
+[20.436725, "o", "r"]
+[20.49883, "o", "o"]
+[20.530947, "o", "m"]
+[20.593148, "o", " "]
+[20.656015, "o", "t"]
+[20.710124, "o", "h"]
+[20.753318, "o", "e"]
+[20.795529, "o", " "]
+[20.857651, "o", "e"]
+[20.889659, "o", "n"]
+[20.941825, "o", "v"]
+[20.993574, "o", "i"]
+[21.025519, "o", "r"]
+[21.07774, "o", "o"]
+[21.119911, "o", "n"]
+[21.182447, "o", "m"]
+[21.245232, "o", "e"]
+[21.297277, "o", "n"]
+[21.350184, "o", "t"]
+[21.403261, "o", " "]
+[21.466236, "o", "i"]
+[21.518512, "o", "n"]
+[21.551256, "o", "s"]
+[21.593832, "o", "t"]
+[21.636443, "o", "e"]
+[21.69895, "o", "a"]
+[21.751668, "o", "d"]
+[21.814316, "o", ","]
+[21.877119, "o", " "]
+[21.940079, "o", "t"]
+[21.982016, "o", "h"]
+[22.024939, "o", "e"]
+[22.057329, "o", "n"]
+[22.12, "o", " "]
+[22.182578, "o", "p"]
+[22.245583, "o", "u"]
+[22.298432, "o", "s"]
+[22.331156, "o", "h"]
+[22.383482, "o", " "]
+[22.445894, "o", "a"]
+[22.477937, "o", "g"]
+[22.509968, "o", "a"]
+[22.572305, "o", "i"]
+[22.62445, "o", "n"]
+[22.676577, "o", "\u001b[0m"]
+[23.378636, "o", "\r\n\u001b[1;32mdev@laptop\u001b[0m \u001b[1;34m~/payments-service\u001b[0m \u001b[33m(main)\u001b[0m $ "]
+[23.980607, "o", "s"]
+[24.01315, "o", "e"]
+[24.07564, "o", "d"]
+[24.138276, "o", " "]
+[24.200279, "o", "-"]
+[24.24266, "o", "i"]
+[24.285356, "o", " "]
+[24.347297, "o", "\""]
+[24.399803, "o", "s"]
+[24.46251, "o", "/"]
+[24.494643, "o", "'"]
+[24.546537, "o", "A"]
+[24.578498, "o", "K"]
+[24.620413, "o", "I"]
+[24.682558, "o", "A"]
+[24.725076, "o", "["]
+[24.76742, "o", "A"]
+[24.819996, "o", "-"]
+[24.882701, "o", "Z"]
+[24.925276, "o", "0"]
+[24.957741, "o", "-"]
+[24.999703, "o", "9"]
+[25.042458, "o", "]"]
+[25.08565, "o", "*"]
+[25.128306, "o", "'"]
+[25.170965, "o", "/"]
+[25.223225, "o", "p"]
+[25.26713, "o", "r"]
+[25.309595, "o", "o"]
+[25.371573, "o", "c"]
+[25.41379, "o", "e"]
+[25.456108, "o", "s"]
+[25.508739, "o", "s"]
+[25.560558, "o", "."]
+[25.602733, "o", "e"]
+[25.63564, "o", "n"]
+[25.668095, "o", "v"]
+[25.719875, "o", "."]
+[25.782146, "o", "A"]
+[25.814132, "o", "W"]
+[25.856136, "o", "S"]
+[25.918229, "o", "_"]
+[25.950837, "o", "A"]
+[25.983399, "o", "C"]
+[26.016254, "o", "C"]
+[26.048189, "o", "E"]
+[26.080177, "o", "S"]
+[26.142135, "o", "S"]
+[26.174603, "o", "_"]
+[26.217065, "o", "K"]
+[26.25915, "o", "E"]
+[26.291324, "o", "Y"]
+[26.343317, "o", "_"]
+[26.375447, "o", "I"]
+[26.42785, "o", "D"]
+[26.469892, "o", "!"]
+[26.511997, "o", "/"]
+[26.554406, "o", "\""]
+[26.596195, "o", " "]
+[26.657993, "o", "s"]
+[26.710215, "o", "r"]
+[26.752694, "o", "c"]
+[26.79485, "o", "/"]
+[26.837026, "o", "s"]
+[26.889444, "o", "3"]
+[26.93177, "o", "."]
+[26.993875, "o", "t"]
+[27.035867, "o", "s"]
+[27.450128, "o", "\r\n"]
+[27.45257, "o", "\u001b[1;32mdev@laptop\u001b[0m \u001b[1;34m~/payments-service\u001b[0m \u001b[33m(main)\u001b[0m $ "]
+[28.054844, "o", "g"]
+[28.117599, "o", "i"]
+[28.160218, "o", "t"]
+[28.202504, "o", " "]
+[28.264437, "o", "d"]
+[28.297362, "o", "i"]
+[28.359393, "o", "f"]
+[28.421598, "o", "f"]
+[28.825299, "o", "\r\n"]
+[28.827657, "o", "\u001b[1mdiff --git a/src/s3.ts b/src/s3.ts\u001b[m\r\n\u001b[1mindex 9f08ca1..45ac067 100644\u001b[m\r\n\u001b[1m--- a/src/s3.ts\u001b[m\r\n\u001b[1m+++ b/src/s3.ts\u001b[m\r\n\u001b[36m@@ -3,7 +3,7 @@\u001b[m \u001b[mimport { S3Client } from '@aws-sdk/client-s3';\u001b[m\r\n export const s3 = new S3Client({\u001b[m\r\n region: 'us-east-1',\u001b[m\r\n credentials: {\u001b[m\r\n\u001b[31m- accessKeyId: 'AKIAIOSFODNN7EXAMPLE',\u001b[m\r\n\u001b[32m+\u001b[m\u001b[32m accessKeyId: process.env.AWS_ACCESS_KEY_ID!,\u001b[m\r\n secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,\u001b[m\r\n },\u001b[m\r\n });\u001b[m\r\n"]
+[28.827914, "o", "\u001b[1;32mdev@laptop\u001b[0m \u001b[1;34m~/payments-service\u001b[0m \u001b[33m(main)\u001b[0m $ "]
+[31.330121, "o", "g"]
+[31.382217, "o", "i"]
+[31.414442, "o", "t"]
+[31.466516, "o", " "]
+[31.528488, "o", "c"]
+[31.590674, "o", "o"]
+[31.652792, "o", "m"]
+[31.684553, "o", "m"]
+[31.736753, "o", "i"]
+[31.778641, "o", "t"]
+[31.831215, "o", " "]
+[31.893221, "o", "-"]
+[31.935749, "o", "q"]
+[31.987713, "o", " "]
+[32.050321, "o", "-"]
+[32.092231, "o", "a"]
+[32.124407, "o", " "]
+[32.18647, "o", "-"]
+[32.251023, "o", "-"]
+[32.303666, "o", "a"]
+[32.366306, "o", "m"]
+[32.418815, "o", "e"]
+[32.481311, "o", "n"]
+[32.533433, "o", "d"]
+[32.565551, "o", " "]
+[32.627914, "o", "-"]
+[32.670066, "o", "-"]
+[32.722091, "o", "n"]
+[32.763981, "o", "o"]
+[32.795939, "o", "-"]
+[32.847767, "o", "e"]
+[32.909859, "o", "d"]
+[32.951618, "o", "i"]
+[33.003527, "o", "t"]
+[33.418903, "o", "\r\n"]
+[33.426492, "o", "\u001b[1;32mdev@laptop\u001b[0m \u001b[1;34m~/payments-service\u001b[0m \u001b[33m(main)\u001b[0m $ "]
+[34.428893, "o", "g"]
+[34.470796, "o", "i"]
+[34.503022, "o", "t"]
+[34.565273, "o", " "]
+[34.62714, "o", "p"]
+[34.689289, "o", "u"]
+[34.731283, "o", "s"]
+[34.773024, "o", "h"]
+[35.176817, "o", "\r\n"]
+[35.247816, "o", "Enumerating objects: 6, done.\r\nCounting objects: 16% (1/6)\rCounting objects: 33% (2/6)\r"]
+[35.247914, "o", "Counting objects: 50% (3/6)\rCounting objects: 66% (4/6)\r"]
+[35.247932, "o", "Counting objects: 83% (5/6)\rCounting objects: 100% (6/6)\r"]
+[35.248374, "o", "Counting objects: 100% (6/6), done.\r\nDelta compression using up to 2 threads\r\nCompressing objects: 25% (1/4)\rCompressing objects: 50% (2/4)\rCompressing objects: 75% (3/4)\rCompressing objects: 100% (4/4)\r"]
+[35.248507, "o", "Compressing objects: 100% (4/4), done.\r\n"]
+[35.248668, "o", "Writing objects: 25% (1/4)\r"]
+[35.249022, "o", "Writing objects: 50% (2/4)\rWriting objects: 75% (3/4)\rWriting objects: 100% (4/4)\rWriting objects: 100% (4/4), 537 bytes | 537.00 KiB/s, done.\r\nTotal 4 (delta 0), reused 0 (delta 0), pack-reused 0\r\n"]
+[35.263992, "o", "remote: Resolving user from token...\u001b[K"]
+[35.264151, "o", "\r\nremote: Checking for empty branch...\u001b[K\r\nremote: Checking repository is authorised...\u001b[K\r\n"]
+[35.264729, "o", "remote: Checking commit messages...\u001b[K\r\nremote: Checking author emails...\u001b[K\r\nremote: Checking push permissions...\u001b[K\r\n"]
+[35.264909, "o", "remote: Fetching remote repository...\u001b[K\r\n"]
+[35.348142, "o", "remote: Writing pack data...\u001b[K\r\n"]
+[35.348367, "o", "remote: Checking for hidden commits...\u001b[K\r\n"]
+[35.348429, "o", "remote: Checking approval status...\u001b[K\r\n"]
+[35.352258, "o", "remote: Running pre-receive hook...\u001b[K\r\nremote: Computing diff...\u001b[K\r\n"]
+[35.358025, "o", "remote: Scanning for secrets...\u001b[K\r\n"]
+[35.358254, "o", "remote: Scanning diff contents...\u001b[K\r\n"]
+[35.358355, "o", "remote: Requesting approval...\u001b[K\r\n"]
+[35.358533, "o", "remote: \t\u001b[K\r\n"]
+[35.358679, "o", "remote: \r\nremote: \r\nremote: \u001b[32mGitProxy has received your push ✅\u001b[0m\u001b[K\r\nremote: \r\nremote: 🔗 Shareable Link\u001b[K\r\n"]
+[35.358714, "o", "remote: \r\nremote: \u001b[34mhttp://localhost:8080/dashboard/push/b418b31c81f74ab1e11ee780051695899e5a6e409f6288da8591c1273ead0e6a\u001b[0m\u001b[K\r\nremote: \r\nremote: \r\nremote: \r\n"]
+[35.359308, "o", "To http://localhost:8000/github.com/my-org/payments-service.git\r\n"]
+[35.359449, "o", " \u001b[31m! [remote rejected]\u001b[m "]
+[35.359527, "o", "main -> main"]
+[35.359648, "o", " ("]
+[35.359726, "o", "approval required"]
+[35.359801, "o", ")"]
+[35.359869, "o", "\r\n"]
+[35.35994, "o", "\u001b[31m"]
+[35.360009, "o", "error: failed to push some refs to 'http://localhost:8000/github.com/my-org/payments-service.git'\r\n"]
+[35.360275, "o", "\u001b[m"]
+[35.360726, "o", "\u001b[1;32mdev@laptop\u001b[0m \u001b[1;34m~/payments-service\u001b[0m \u001b[33m(main)\u001b[0m $ "]
+[41.362957, "o", "\u001b[?25h"]