summaryrefslogtreecommitdiff
path: root/src/scripts
diff options
context:
space:
mode:
authorbdunahu <bdunahu@operationnull.com>2026-04-27 22:16:12 -0400
committerbdunahu <bdunahu@operationnull.com>2026-04-28 00:15:09 -0400
commit9e143d1d84817ec7e6d139d234f0fff07749621c (patch)
tree7565eac131cc3528d33d5ea3597cdd8006fdb968 /src/scripts
initial commitHEADmaster
Diffstat (limited to 'src/scripts')
-rwxr-xr-xsrc/scripts/actions_to_type.sh77
-rw-r--r--src/scripts/build-action.sh135
-rw-r--r--src/scripts/channels.scm20
-rwxr-xr-xsrc/scripts/repos_to_actions_map.sh53
4 files changed, 285 insertions, 0 deletions
diff --git a/src/scripts/actions_to_type.sh b/src/scripts/actions_to_type.sh
new file mode 100755
index 0000000..5d93955
--- /dev/null
+++ b/src/scripts/actions_to_type.sh
@@ -0,0 +1,77 @@
+#!/usr/bin/env bash
+# kenku --- crawl and reproduce github actions
+# Copyright © 2026 bdunahu <bdunahu@operationnull.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+#
+# Takes a file with a repository identifier per line, like this:
+#
+# actions/deploy-pages v4
+# actions/upload-pages-artifact v4
+# astral-sh/setup-uv v7
+# actions/setup-python v2
+# actions/checkout v2
+#
+# And writes an equivalent file with what it's using. 'using' in this case can
+# be one of the standard action types in the github actions lingo: 'node',
+# 'docker', or 'composite'.
+# The `actions.yaml` or `actions.yml` file does a pretty good job explaining
+# what is used or not.
+
+function curl_action {
+ curl -s \
+ -H "Accept: application/vnd.github+json" \
+ -H "Authorization: Bearer ${TOKEN}" \
+ "https://api.github.com/repos/$1?ref=$2"
+}
+
+function find_action {
+ owner=$(echo "$1" | awk -F'/' '{print $(1)}')
+ repo=$(echo "$1" | awk -F'/' '{print $(2)}')
+ fname=$(echo "$1" | cut -d'/' -f3-)
+ sha="$2"
+
+ path="$owner/$repo/contents/$fname"
+
+ if [[ "$path" =~ \.(yml|yaml)$ ]]; then
+ action=$(curl_action "$path" "$sha")
+ exists=true
+ else
+ for c in action.yml action.yaml; do
+ p="$path/$c"
+
+ action=$(curl_action "$p" "$sha")
+
+ # endpoint doesn't exist
+ exists=$(echo "$action" | jq -e 'has("message") | not')
+ [[ "$exists" == true ]] && break
+ done
+ fi
+
+ using=$("$exists" && {
+ echo "$action" \
+ | jq -r '.content' \
+ | base64 -d \
+ | grep -E '^\s*"?using"?:' \
+ | sed -E 's/.*"?using"?:[[:space:]]*//'
+ } || echo "NO_FILE"
+ )
+ [[ -z "$using" ]] && using="NO_USING"
+ echo "$1 $sha $using"
+}
+
+while read -r action sha; do
+ find_action "$action" "$sha"
+done
diff --git a/src/scripts/build-action.sh b/src/scripts/build-action.sh
new file mode 100644
index 0000000..9c1d502
--- /dev/null
+++ b/src/scripts/build-action.sh
@@ -0,0 +1,135 @@
+#!/usr/bin/env bash
+# kenku --- crawl and reproduce github actions
+# Copyright © 2026 bdunahu <bdunahu@operationnull.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+function get_output_file {
+ local output_file action_file
+ action_file="action.yml"
+ [ ! -f "$action_file" ] && action_file="action.yaml"
+ output_file=$(grep -E '^\s*main:\s*' "${TO_ACT}${action_file}" | awk '{print $2}')
+ output_file=${output_file//\"/}
+ echo ${output_file//\'/}
+}
+
+function script_exists {
+ npm run | grep -q "^ $1"
+}
+
+ALL="$1"
+SHA="$2"
+DIR="$3"
+BUILD_FAILURE_DIR="$4"
+MISSING_ARTIFACT_DIR="$5"
+MAYBE_REPRODUCIBLE_DIR="$6"
+REPRODUCIBLE_DIR="$7"
+
+REPO_PRINTABLE="${ALL//\//_}_$SHA"
+# holds temporary print strings
+
+REPO=$(echo "$ALL" | awk -F'/' '{print $(1)}')
+TO_ACT=$(echo "$ALL" | awk -F'/' '{print $(2)}')
+REPO="$REPO/$TO_ACT"
+TO_ACT=$(echo "$ALL" | cut -d'/' -f3-)
+[[ -n "$TO_ACT" ]] && TO_ACT="$TO_ACT/"
+
+BUILD_DIR=$(mktemp -d)
+cd "$BUILD_DIR"
+
+echo "Cloning $REPO..."
+git clone "https://github.com/$REPO.git" repo > /dev/null 2>&1
+cd repo
+echo "Checking out $SHA"
+git checkout "$SHA" > /dev/null 2>&1
+
+# actions.yml refers to actions relatively, so if we parse
+# ../dist/foo/ as the action final build dir, we need to
+# refer to it relative to the curr dir of the script
+# this is one way
+DIST="$TO_ACT$(get_output_file)"
+# some actions just name an index.js in the root dir.
+# In cases they name a directory, we'll diff the full thing.
+[ "$(dirname "$DIST")" != "." ] && DIST="$(dirname "$DIST")"
+REFERENCE_DIST="$DIST.1"
+echo "Saving $DIST to $REFERENCE_DIST"
+
+mv "$DIST" "$REFERENCE_DIST"
+
+cd "$DIR"
+echo "Installing packages..."
+
+INSTALL=$(npm ci 2>&1)
+
+echo "Attempting to build..."
+
+TMP="owo what's the build command"
+# surely ONE of these will work...
+if COMM="release"; script_exists "$COMM"; then
+ echo "Trying '$COMM'..."
+ TMP=$(npm run "$COMM" 2>&1)
+elif COMM="package"; script_exists "$COMM"; then
+ echo "Trying '$COMM'..."
+ TMP=$(npm run "$COMM" 2>&1)
+elif COMM="bundle"; script_exists "$COMM"; then
+ echo "Trying '$COMM'..."
+ TMP=$(npm run "$COMM" 2>&1)
+elif COMM="build"; script_exists "$COMM"; then
+ echo "Trying '$COMM'..."
+ TMP=$(npm run "$COMM" 2>&1)
+fi
+
+# if the build fails, the developers may have failed to setup
+# the environment properly, or it uses deprecated features.
+# It may be that there is no build command at all! This needs
+# manual review.
+if [[ $? -ne 0 ]]; then
+ echo "$ALL did not build."
+ echo "$INSTALL" > "$BUILD_FAILURE_DIR/${REPO_PRINTABLE}.log"
+ echo "$TMP" >> "$BUILD_FAILURE_DIR/${REPO_PRINTABLE}.log"
+ exit 0 #don't kill outer script
+fi
+
+# return back to where we were
+cd "$BUILD_DIR"
+cd repo
+
+if [[ ! -d "$DIST" ]]; then
+ # TODO: if the dist dir wasn't produced, then the commands
+ # used were likely wrong
+ echo "$ALL did not produce artifacts."
+ echo "$INSTALL" >> "$MISSING_ARTIFACT_DIR/${REPO_PRINTABLE}.log"
+ echo "$TMP" >> "$MISSING_ARTIFACT_DIR/${REPO_PRINTABLE}.log"
+ exit 0
+fi
+
+# diffoscope will output binary diffs if line endings are not
+# comparable. --force forces it to convert binary files too.
+find "$REFERENCE_DIST" -type f -exec dos2unix --force {} \;
+
+# TODO: solves path errors in containers when using global install
+mkdir -p "$HOME/.npm-global"
+npm config set prefix "$HOME/.npm-global"
+export PATH="$HOME/.npm-global/bin:$PATH"
+
+# diffoscope uses to compare pretty
+npm install -g js-beautify
+
+diffoscope "$DIST" "$REFERENCE_DIST" \
+ --exclude-directory-metadata=yes \
+ --html "$MAYBE_REPRODUCIBLE_DIR/${REPO_PRINTABLE}.html"
+if [[ ! -f "$MAYBE_REPRODUCIBLE_DIR/${REPO_PRINTABLE}.html" ]]; then
+ touch "$REPRODUCIBLE_DIR/${REPO_PRINTABLE}.flag"
+ exit 0
+fi
diff --git a/src/scripts/channels.scm b/src/scripts/channels.scm
new file mode 100644
index 0000000..b49849d
--- /dev/null
+++ b/src/scripts/channels.scm
@@ -0,0 +1,20 @@
+(list (channel
+ (name 'guix)
+ (url "https://codeberg.org/guix/guix")
+ (branch "master")
+ (commit "c3c2f3be04364e3f616bfcc38875b112bedbe901")
+ (introduction
+ (make-channel-introduction
+ "9edb3f66fd807b096b48283debdcddccfea34bad"
+ (openpgp-fingerprint
+ "BBB0 2DDF 2CEA F6A8 0D1D E643 A2A0 6DF2 A33A 54FA"))))
+ (channel
+ (name 'tanelorn)
+ (url "https://git.operationnull.com/tanelorn.git")
+ (branch "master")
+ (commit "1c25e9f613d8654f800f9be1d4b232ec9de25aa0")
+ (introduction
+ (make-channel-introduction
+ "3960d45383c672f8aacab8e354824793256c9d29"
+ (openpgp-fingerprint
+ "5550 5CA6 9DE5 D342 7F31 F9AE 5F86 6C65 2A34 C996")))))
diff --git a/src/scripts/repos_to_actions_map.sh b/src/scripts/repos_to_actions_map.sh
new file mode 100755
index 0000000..2216a5a
--- /dev/null
+++ b/src/scripts/repos_to_actions_map.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/env bash
+# kenku --- crawl and reproduce github actions
+# Copyright © 2026 bdunahu <bdunahu@operationnull.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+# Takes a file with one repo per line and outputs a master list
+# of REPO, ACTION pairs. This script takes a long time to run.
+# There is an obvious part of this script that is pretty gross.
+# I got it working sometime in early march and have forgotten
+# why it does what it does.
+
+function get_flows {
+ curl -s \
+ -H "Accept: application/vnd.github+json" \
+ -H "Authorization: Bearer $TOKEN" \
+ "https://api.github.com/repos/$1/$2/contents/.github/workflows"
+}
+
+function has_flows {
+ echo "$1" \
+ | jq -e 'type == "object" and has("message") | not' >/dev/null 2>&1
+}
+
+function get_url {
+ local owner repo flows
+ owner=$(echo "$1" | awk -F'/' '{print $(NF-1)}')
+ repo=$(echo "$1" | awk -F'/' '{print $(NF)}')
+
+ flows=$(get_flows "$owner" "$repo")
+ has_flows "$flows" &&
+ echo "$flows" | jq -r '.[] | select(.type=="file") | .download_url' \
+ | xargs -n1 sh -c '
+ for url do
+ curl -s "$url" | grep -E "^\s*-?\s*uses:" | sed "s|.*uses:\s*|$1 |"
+ done
+ ' _ "$1" # passes arg to sh -c
+}
+
+while read -r url; do
+ get_url "$url"
+done