Skip to content

feat(upload-s3-artifact): run on the node24 runtime, implemented in TypeScript - #267

Merged
joakimen merged 1 commit into
masterfrom
feat/upload-s3-artifact-typescript
Sep 15, 2026
Merged

joakimen merged 1 commit into
masterfrom
feat/upload-s3-artifact-typescript

Conversation

@joakimen

@joakimen joakimen commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Moves the action to the node24 runtime. Archives with fflate and uploads with the AWS SDK, so it no longer needs zip, sha256sum or the aws CLI on the runner.

Unit tests now cover the key derivation and the archiving, including that an entry keeps its unix mode — a zip writer that drops it silently loses the executable bit.

Behaviour

An archive that would need Zip64, above 65535 entries or 4 GB, is refused rather than written: fflate does not emit those extensions and does not fail either, it corrupts the header.

An empty target directory now fails, as zip -r did.

Uploads go through the SDK's multipart upload, since a single PutObject stops at 5 GB.

Comment thread lib/archive.ts Outdated
Comment thread lib/archive.ts
Comment on lines +50 to +59

while (pending.length > 0) {
const path = pending.pop() as string
const stats = statSync(path)

if (!stats.isDirectory()) {
entries.push({
name: toEntryName(relative(root, path)),
mode: stats.mode,
content: new Uint8Array(readFileSync(path)),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential file inclusion attack via reading file - high severity
If an attacker can control the input leading into the ReadFile function, they might be able to read sensitive files and launch further attacks with that information.

Show fix
Suggested change
while (pending.length > 0) {
const path = pending.pop() as string
const stats = statSync(path)
if (!stats.isDirectory()) {
entries.push({
name: toEntryName(relative(root, path)),
mode: stats.mode,
content: new Uint8Array(readFileSync(path)),
const resolvedRoot = path.resolve(root)
while (pending.length > 0) {
const path = pending.pop() as string
const stats = statSync(path)
if (!stats.isDirectory()) {
const resolvedPath = path.resolve(path)
const relativePath = path.relative(resolvedRoot, resolvedPath)
if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
throw new Error('Invalid file path')
}
entries.push({
name: toEntryName(relative(root, path)),
mode: stats.mode,
content: new Uint8Array(readFileSync(resolvedPath)),

Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AikidoSec ignore: workflow author supplies these paths and controls the workflow execution

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Based on your feedback, we ignored this issue because of the following reason:

workflow author supplies these paths and controls the workflow execution

…ypeScript

Archives with fflate and uploads with the AWS SDK, so the action no longer
needs zip, sha256sum or the aws CLI on the runner. Archive entries keep their
unix mode, which is what carries the executable bit.

Refuses an archive that would need Zip64 rather than writing a corrupt one, and
fails on an empty target directory as `zip -r` did.

Inputs, outputs and the S3 key for given bytes are unchanged.
@joakimen
joakimen force-pushed the feat/upload-s3-artifact-typescript branch from 142601d to 178538b Compare September 15, 2026 10:43
@joakimen
joakimen merged commit 707bd81 into master Sep 15, 2026
4 checks passed
@joakimen
joakimen deleted the feat/upload-s3-artifact-typescript branch September 15, 2026 11:18
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 1.15.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant