From 6d19ed571c5b118e1aa7601b1c7cd7a9490dfb33 Mon Sep 17 00:00:00 2001 From: default Date: Fri, 17 Oct 2025 19:00:07 -0500 Subject: [PATCH 1/6] Add [copyparty] module --- .icons/copyparty.svg | 210 ++++++++++++++++++ registry/djarbz/.images/avatar.png | Bin 0 -> 1557 bytes .../djarbz/.images/copyparty_screenshot.png | Bin 0 -> 39447 bytes registry/djarbz/README.md | 11 + registry/djarbz/modules/copyparty/README.md | 68 ++++++ .../modules/copyparty/copyparty.tftest.hcl | 181 +++++++++++++++ registry/djarbz/modules/copyparty/main.tf | 174 +++++++++++++++ registry/djarbz/modules/copyparty/run.sh | 100 +++++++++ registry/djarbz/repo_setup.md | 37 +++ 9 files changed, 781 insertions(+) create mode 100644 .icons/copyparty.svg create mode 100644 registry/djarbz/.images/avatar.png create mode 100644 registry/djarbz/.images/copyparty_screenshot.png create mode 100644 registry/djarbz/README.md create mode 100644 registry/djarbz/modules/copyparty/README.md create mode 100644 registry/djarbz/modules/copyparty/copyparty.tftest.hcl create mode 100644 registry/djarbz/modules/copyparty/main.tf create mode 100755 registry/djarbz/modules/copyparty/run.sh create mode 100644 registry/djarbz/repo_setup.md diff --git a/.icons/copyparty.svg b/.icons/copyparty.svg new file mode 100644 index 000000000..2c4f0d045 --- /dev/null +++ b/.icons/copyparty.svg @@ -0,0 +1,210 @@ + + + copyparty_logo + + + + + + + + + + + + image/svg+xml + + copyparty_logo + github.com/9001/copyparty + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/registry/djarbz/.images/avatar.png b/registry/djarbz/.images/avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..f60192032e0581ddbb88633f9c8efaa893d41953 GIT binary patch literal 1557 zcmeAS@N?(olHy`uVBq!ia0y~yU|a&i985rwk9xzp%(1l;$4Bkqz=}n|~?D z=Uv~5XV3dEF=jZYYG{^)MzPhqmz?(bpe$|Ebeev}3B8If6niSxZe3>1@W*O8{mQKm e`V0*J|E~~M^7r`XTnjAj89ZJ6T-G@yGywqQMEvFe literal 0 HcmV?d00001 diff --git a/registry/djarbz/.images/copyparty_screenshot.png b/registry/djarbz/.images/copyparty_screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..690c716f9e2184197498a6d6a6a70a426f7c63ed GIT binary patch literal 39447 zcmd42bx@qm8ZU@zkl=2?-CY6!65M5QNMH!=8r(I(ZE$zO;7+h$GdK(cw*Z3^Bm`LU zopZMC-E+6<*4=-$Yl>-k`ti4a-90Zcn(A+Huqdz)5D;*b-pOktAfN&f5Rh;%ke_?3 zMWsLp2*?PUs=5kqT~wcY{(oC2X*g-bkEIaE2wBVo+b@_vfrI_B8a@DCm^Dpm^kq-P$k8B5So$g>3!ul&8wyh7|%Xh5#j@ z!Z9($MMb>~jJ$0nuPZX7LGe;vW-JmaOm>dppVADyzUT($8241kDJcV-qcv2_cuP~I zY=e|Od~lbRerM?|A6;qu^z>xpEG@0U>cpk@z3^>*e*5avL}c*?4J)C&HVt|Iz*PtW2706{*^tUc

WVLNJcUG;# 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 literal 0 HcmV?d00001 diff --git a/registry/djarbz/README.md b/registry/djarbz/README.md new file mode 100644 index 000000000..2319441ab --- /dev/null +++ b/registry/djarbz/README.md @@ -0,0 +1,11 @@ +--- +display_name: "Austin" +bio: "IT Pro by day, script kiddie at night." +avatar: "./.images/avatar.png" +github: "djarbz" +status: "community" +--- + +# Austin + +I like to program as a hobby. diff --git a/registry/djarbz/modules/copyparty/README.md b/registry/djarbz/modules/copyparty/README.md new file mode 100644 index 000000000..f3e6ca3aa --- /dev/null +++ b/registry/djarbz/modules/copyparty/README.md @@ -0,0 +1,68 @@ +--- +display_name: copyparty +description: A web based file explorer alternative to Filebrowser. +icon: ../../../../.icons/copyparty.svg +verified: false +tags: [files, filebrowser, web, copyparty] +--- + +# copyparty + + + +This module installs Copyparty, an alternative to Filebrowser. +[Copyparty](https://github.com/9001/copyparty) is a portable file server with accelerated resumable uploads, dedup, WebDAV, FTP, TFTP, zeroconf, media indexer, thumbnails++ all in one file, no deps + +```tf +module "copyparty" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/djarbz/copyparty/coder" + version = "0.1.0" +} +``` + + + +![copyparty-browser-fs8](../../.images/copyparty_screenshot.png) + +## Examples + +### Example 1 + +Some basic command line options: + +```tf +module "copyparty" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/djarbz/copyparty/coder" + version = "0.1.0" + agent_id = coder_agent.example.id + arguments = [ + "-v", "/home/coder/:/home:r", # Share home directory (read-only) + "-v", "${local.repo_dir}:/repo:rw", # Share project directory (read-write) + "-e2dsa", # Enables general file indexing" + ] +} +``` + +### Example 2 + +```tf +module "copyparty" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/djarbz/copyparty/coder" + version = "0.1.0" + agent_id = coder_agent.example.id + subdomain = true + arguments = [ + "-v", "/tmp:/tmp:r", # Share tmp directory (read-only) + "-v", "/home/coder/:/home:rw", # Share home directory (read-write) + "-v", "${local.root_dir}:/work:A:c,dotsrch", # Share work directory (All Perms) + "-e2dsa", # Enables general file indexing" + "--re-maxage", "900", # Rescan filesystem for changes every SEC + "--see-dots", # Show dotfiles by default if user has correct permissions on volume + "--xff-src=lan", # List of trusted reverse-proxy CIDRs (comma-separated) or `lan` for private IPs. + "--rproxy", "1", # Which ip to associate clients with, index of X-FWD IP. + ] +} +``` diff --git a/registry/djarbz/modules/copyparty/copyparty.tftest.hcl b/registry/djarbz/modules/copyparty/copyparty.tftest.hcl new file mode 100644 index 000000000..e6fab8439 --- /dev/null +++ b/registry/djarbz/modules/copyparty/copyparty.tftest.hcl @@ -0,0 +1,181 @@ +# --- Test Case 1: Required Variables --- +run "plan_with_required_vars" { + command = plan + + variables { + agent_id = "example-agent-id" + } +} + +# --- Test Case 2: Coder App URL uses custom port --- +run "app_url_uses_port" { + command = plan + + variables { + agent_id = "example-agent-id" + port = 19999 + } + + assert { + condition = resource.coder_app.copyparty.url == "http://localhost:19999" + error_message = "Expected copyparty app URL to include configured port" + } +} + +# --- Test Case 3: Default Values --- +run "test_defaults" { + # This run block applies the module with default values + # (except for the required 'agent_id' provided above). + + variables { + agent_id = "example-agent-id" + } + + # --- Asserts for coder_app "copyparty" --- + assert { + condition = resource.coder_app.copyparty.display_name == "copyparty" + error_message = "Default display_name is incorrect" + } + + assert { + condition = resource.coder_app.copyparty.slug == "copyparty" + error_message = "Default slug is incorrect" + } + + assert { + condition = resource.coder_app.copyparty.url == "http://localhost:3923" + error_message = "Default URL is incorrect, expected port 3923" + } + + assert { + condition = resource.coder_app.copyparty.subdomain == false + error_message = "Default subdomain should be false" + } + + assert { + condition = resource.coder_app.copyparty.share == "owner" + error_message = "Default share value should be 'owner'" + } + + assert { + condition = resource.coder_app.copyparty.open_in == "slim-window" + error_message = "Default open_in value should be 'slim-window'" + } + + # --- Asserts for coder_script "copyparty" --- + assert { + condition = coder_script.copyparty.display_name == "copyparty" + error_message = "Script display_name is incorrect" + } + + # Check rendered script content (this assumes your run.sh uses the variables) + assert { + condition = strcontains(coder_script.copyparty.script, "PORT=\"3923\"") + error_message = "Script content does not reflect default port" + } + + assert { + condition = strcontains(coder_script.copyparty.script, "LOG_PATH=\"/tmp/copyparty.log\"") + error_message = "Script content does not reflect default log_path" + } + + assert { + condition = strcontains(coder_script.copyparty.script, "IFS=',' read -r -a ARGUMENTS \u003c\u003c\u003c \"\"") + error_message = "Script content does not reflect default empty arguments" + } +} + +# --- Test Case 4: Custom Values --- +run "test_custom_values" { + # Override default variables for this specific run + variables { + agent_id = "example-agent-id" + port = 8080 + slug = "my-custom-app" + display_name = "My Custom App" + share = "authenticated" + open_in = "tab" + pinned_version = "v1.2.3" + arguments = ["--verbose", "-v"] + log_path = "/var/log/custom.log" + } + + # --- Asserts for coder_app "copyparty" --- + assert { + condition = resource.coder_app.copyparty.display_name == "My Custom App" + error_message = "Custom display_name was not applied" + } + + assert { + condition = resource.coder_app.copyparty.slug == "my-custom-app" + error_message = "Custom slug was not applied" + } + + assert { + condition = resource.coder_app.copyparty.url == "http://localhost:8080" + error_message = "Custom port was not applied to URL" + } + + assert { + condition = resource.coder_app.copyparty.share == "authenticated" + error_message = "Custom share value was not applied" + } + + assert { + condition = resource.coder_app.copyparty.open_in == "tab" + error_message = "Custom open_in value was not applied" + } + + # --- Asserts for coder_script "copyparty" --- + assert { + condition = strcontains(coder_script.copyparty.script, "PORT=\"8080\"") + error_message = "Script content does not reflect custom port" + } + + assert { + condition = strcontains(coder_script.copyparty.script, "PINNED_VERSION=\"v1.2.3\"") + error_message = "Script content does not reflect custom pinned_version" + } + + assert { + condition = strcontains(coder_script.copyparty.script, "IFS=',' read -r -a ARGUMENTS \u003c\u003c\u003c \"--verbose,-v\"") + error_message = "Script content does not reflect custom arguments" + } + + assert { + condition = strcontains(coder_script.copyparty.script, "LOG_PATH=\"/var/log/custom.log\"") + error_message = "Script content does not reflect custom log_path" + } +} + +# --- Test Case 5: Validation Failure (open_in) --- +run "test_invalid_open_in" { + # This is a 'plan' test that expects a failure + command = plan + + variables { + agent_id = "example-agent-id" + open_in = "invalid-value" + } + + # Expect this plan to fail due to the validation rule in 'var.open_in' + expect_failures = [ + var.open_in, + ] +} + +# --- Test Case 6: Validation Failure (share) --- +run "test_invalid_share" { + # This is a 'plan' test that expects a failure + command = plan + + variables { + agent_id = "example-agent-id" + share = "everyone" # This is not 'owner', 'authenticated', or 'public' + } + + # Expect this plan to fail due to the validation rule in 'var.share' + expect_failures = [ + var.share, + ] +} diff --git a/registry/djarbz/modules/copyparty/main.tf b/registry/djarbz/modules/copyparty/main.tf new file mode 100644 index 000000000..3a975c947 --- /dev/null +++ b/registry/djarbz/modules/copyparty/main.tf @@ -0,0 +1,174 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + coder = { + source = "coder/coder" + version = ">= 2.5" + } + } +} + +locals { + # A built-in icon like "/icon/code.svg" or a full URL of icon + icon_url = "https://raw.githubusercontent.com/9001/copyparty/refs/heads/hovudstraum/docs/logo.svg" + # a map of all possible values + # options = { + # "Option 1" = { + # "name" = "Option 1", + # "value" = "1" + # "icon" = "/emojis/1.png" + # } + # "Option 2" = { + # "name" = "Option 2", + # "value" = "2" + # "icon" = "/emojis/2.png" + # } + # } +} + +# Add required variables for your modules and remove any unneeded variables +variable "agent_id" { + type = string + description = "The ID of a Coder agent." +} + +variable "log_path" { + type = string + description = "The path to log copyparty to." + default = "/tmp/copyparty.log" +} + +variable "port" { + type = number + description = "ports to listen on (comma/range); ignored for unix-sockets (default: 3923)" + default = 3923 +} + +variable "slug" { + type = string + description = "The slug for the copyparty application." + default = "copyparty" +} + +variable "display_name" { + type = string + description = "The display name for the copyparty application." + default = "copyparty" +} + +variable "group" { + type = string + description = "The name of a group that this app belongs to." + default = null +} + +variable "open_in" { + type = string + description = <<-EOT + Determines where the app will be opened. Valid values are `"tab"` and `"slim-window" (default)`. + `"tab"` opens in a new tab in the same browser window. + `"slim-window"` opens a new browser window without navigation controls. + EOT + default = "slim-window" + validation { + condition = contains(["tab", "slim-window"], var.open_in) + error_message = "The 'open_in' variable must be one of: 'tab', 'slim-window'." + } +} + +variable "subdomain" { + type = bool + description = <<-EOT + Determines whether the app will be accessed via it's own subdomain or whether it will be accessed via a path on Coder. + If wildcards have not been setup by the administrator then apps with "subdomain" set to true will not be accessible. + EOT + default = false +} + +variable "share" { + type = string + default = "owner" + validation { + condition = var.share == "owner" || var.share == "authenticated" || var.share == "public" + error_message = "Incorrect value. Please set either 'owner', 'authenticated', or 'public'." + } +} + +# variable "mutable" { +# type = bool +# description = "Whether the parameter is mutable." +# default = true +# } + +variable "order" { + type = number + description = "The order determines the position of app in the UI presentation. The lowest order is shown first and apps with equal order are sorted by name (ascending order)." + default = null +} +# Add other variables here + +variable "pinned_version" { + type = string + description = "Install a specific version in semver format (v1.19.16)." + default = "" +} + +variable "arguments" { + type = list(string) + description = "A list of arguments to pass to the application." + default = [] +} + + +resource "coder_script" "copyparty" { + agent_id = var.agent_id + display_name = "copyparty" + icon = local.icon_url + script = templatefile("${path.module}/run.sh", { + LOG_PATH : var.log_path, + PORT : var.port, + PINNED_VERSION : var.pinned_version, + ARGUMENTS : join(",", var.arguments), + }) + run_on_start = true + run_on_stop = false +} + +resource "coder_app" "copyparty" { + agent_id = var.agent_id + slug = var.slug + display_name = var.display_name + url = "http://localhost:${var.port}" + icon = local.icon_url + subdomain = var.subdomain + share = var.share + order = var.order + group = var.group + open_in = var.open_in + + # Remove if the app does not have a healthcheck endpoint + healthcheck { + url = "http://localhost:${var.port}" + interval = 5 + threshold = 6 + } +} + +# data "coder_parameter" "copyparty" { +# type = "list(string)" +# name = "copyparty" +# display_name = "copyparty" +# icon = local.icon_url +# mutable = var.mutable +# default = local.options["Option 1"]["value"] + +# dynamic "option" { +# for_each = local.options +# content { +# icon = option.value.icon +# name = option.value.name +# value = option.value.value +# } +# } +# } diff --git a/registry/djarbz/modules/copyparty/run.sh b/registry/djarbz/modules/copyparty/run.sh new file mode 100755 index 000000000..46451f878 --- /dev/null +++ b/registry/djarbz/modules/copyparty/run.sh @@ -0,0 +1,100 @@ +#!/usr/bin/env bash + +# Convert templated variables to shell variables +# This variable is assigned to itself, so the assignment does nothing. +# shellcheck disable=SC2269 +LOG_PATH="${LOG_PATH}" + +# Ports to listen on (comma/range); ignored for unix-sockets (default: 3923) +PORT="${PORT}" +# Pinned version (e.g., v1.19.16); overrides latest release discovery if set +PINNED_VERSION="${PINNED_VERSION}" +# Custom CLI Arguments# The variable from Terraform is a single, comma-separated string. +# We need to split it into a proper bash array using the comma (,) as the delimiter. +IFS=',' read -r -a ARGUMENTS <<< "${ARGUMENTS}" + +# VARIABLE appears unused. Verify use (or export if used externally). +# shellcheck disable=SC2034 +MODULE_NAME="Copyparty" + +# VARIABLE appears unused. Verify use (or export if used externally). +# shellcheck disable=SC2034 +BOLD='\033[0;1m' + +printf '%sInstalling %s ...\n\n' "$${BOLD}" "$${MODULE_NAME}" + +# Add code here +# Use variables from the templatefile function in main.tf +# e.g. LOG_PATH, PORT, etc. + +printf "🐍 Verifying Python 3 installation...\n" +if ! command -v python3 &> /dev/null; then + printf "❌ Python3 could not be found. Please install it to continue.\n" + exit 1 +fi +printf "✅ Python3 is installed.\n\n" + +RELEASE_TO_INSTALL="" +# Install provided version to pin, otherwise discover latest github release from `https://github.com/9001/copyparty`. +if [[ -n "$${PINNED_VERSION}" ]]; then + printf "📌 Pinned version specified: %s\n" "$${PINNED_VERSION}" + # Verify that it is in v#.#.# format + if [[ ! "$${PINNED_VERSION}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + printf "❌ Invalid format for PINNED_VERSION. Expected 'v#.#.#' (e.g., v1.19.16).\n" + exit 1 + fi + RELEASE_TO_INSTALL="$${PINNED_VERSION}" + printf "✅ Using pinned version %s.\n\n" "$${RELEASE_TO_INSTALL}" +else + printf "🔎 Discovering latest release from GitHub...\n" + # Use curl to get the latest release tag from the GitHub API and sed to parse it + LATEST_RELEASE=$(curl -fsSL https://api.github.com/repos/9001/copyparty/releases/latest | grep '"tag_name":' | sed -E 's/.*"(v[^"]+)".*/\1/') + if [[ -z "$${LATEST_RELEASE}" ]]; then + printf "❌ Could not determine the latest release. Please check your internet connection.\n" + exit 1 + fi + RELEASE_TO_INSTALL="$${LATEST_RELEASE}" + printf "🏷️ Latest release is %s.\n\n" "$${RELEASE_TO_INSTALL}" +fi + +# Download appropriate release version assets: `copyparty-sfx.py` and `helptext.html`. +printf "🚀 Downloading copyparty v%s...\n" "$${RELEASE_TO_INSTALL}" +DOWNLOAD_URL="https://github.com/9001/copyparty/releases/download/$${RELEASE_TO_INSTALL}" + +printf "⏬ Downloading copyparty-sfx.py...\n" +if ! curl -fsSL -o /tmp/copyparty-sfx.py "$${DOWNLOAD_URL}/copyparty-sfx.py"; then + printf "❌ Failed to download copyparty-sfx.py.\n" + exit 1 +fi + +printf "⏬ Downloading helptext.html...\n" +if ! curl -fsSL -o /tmp/helptext.html "$${DOWNLOAD_URL}/helptext.html"; then + # This is not a fatal error, just a warning. + printf "⚠️ Could not download helptext.html. The application will still work.\n" +fi + +chmod +x /tmp/copyparty-sfx.py +printf "✅ Download complete.\n\n" + +printf "🥳 Installation complete!\n\n" + +# Build a clean, quoted string of the command for logging purposes only. +log_command="python3 /tmp/copyparty-sfx.py -p '$${PORT}'" +for arg in "$${ARGUMENTS[@]}"; do + # printf "DEBUG: ARG [$${arg}]\n" + log_command+=" '$${arg}'" +done + +# Clear the log file and write the header and command string using printf. +{ + printf "=== Starting copyparty at %s ===\n" "$(date)" + printf "EXECUTING: %s\n" "$${log_command}" +} > "$${LOG_PATH}" + +printf "👷 Starting %s in background...\n\n" "$${MODULE_NAME}" + +# Execute the actual command using the robust array expansion. +# Then, append its output (stdout and stderr) to the log file. +python3 /tmp/copyparty-sfx.py -p "$${PORT}" "$${ARGUMENTS[@]}" >> "$${LOG_PATH}" 2>&1 & + +printf "✅ Service started. Check logs at %s\n\n" "$${LOG_PATH}" diff --git a/registry/djarbz/repo_setup.md b/registry/djarbz/repo_setup.md new file mode 100644 index 000000000..a8ec422d5 --- /dev/null +++ b/registry/djarbz/repo_setup.md @@ -0,0 +1,37 @@ +# Notes on Environment Setup + +## Install Node + +```bash +curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash +export NVM_DIR="$HOME/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" +[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" +nvm install node +npm install +``` + +## Install Bun + +```bash +npm install -g bun +``` + +## Install Terraform + +```bash +sudo apt-get update && sudo apt-get install -y gnupg software-properties-common +curl -fsSL https://apt.releases.hashicorp.com/gpg \ + | gpg --dearmor \ + | sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg > /dev/null +gpg --no-default-keyring \ + --keyring /usr/share/keyrings/hashicorp-archive-keyring.gpg \ + --fingerprint +echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(grep -oP '(?<=UBUNTU_CODENAME=).*' /etc/os-release || lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list +sudo apt update +sudo apt-get install -y terraform +``` + +## Install Extenstions + +- hashicorp.terraform From 1bf621aa4f3791182329171a3289a5ad283851e6 Mon Sep 17 00:00:00 2001 From: default Date: Fri, 17 Oct 2025 19:05:06 -0500 Subject: [PATCH 2/6] Fix Prettier --- registry/djarbz/modules/copyparty/README.md | 24 ++++++++++----------- registry/djarbz/modules/copyparty/run.sh | 10 ++++----- registry/djarbz/repo_setup.md | 13 ++++++++++- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/registry/djarbz/modules/copyparty/README.md b/registry/djarbz/modules/copyparty/README.md index f3e6ca3aa..70119d598 100644 --- a/registry/djarbz/modules/copyparty/README.md +++ b/registry/djarbz/modules/copyparty/README.md @@ -49,20 +49,20 @@ module "copyparty" { ```tf module "copyparty" { - count = data.coder_workspace.me.start_count - source = "registry.coder.com/djarbz/copyparty/coder" - version = "0.1.0" - agent_id = coder_agent.example.id + count = data.coder_workspace.me.start_count + source = "registry.coder.com/djarbz/copyparty/coder" + version = "0.1.0" + agent_id = coder_agent.example.id subdomain = true arguments = [ - "-v", "/tmp:/tmp:r", # Share tmp directory (read-only) - "-v", "/home/coder/:/home:rw", # Share home directory (read-write) - "-v", "${local.root_dir}:/work:A:c,dotsrch", # Share work directory (All Perms) - "-e2dsa", # Enables general file indexing" - "--re-maxage", "900", # Rescan filesystem for changes every SEC - "--see-dots", # Show dotfiles by default if user has correct permissions on volume - "--xff-src=lan", # List of trusted reverse-proxy CIDRs (comma-separated) or `lan` for private IPs. - "--rproxy", "1", # Which ip to associate clients with, index of X-FWD IP. + "-v", "/tmp:/tmp:r", # Share tmp directory (read-only) + "-v", "/home/coder/:/home:rw", # Share home directory (read-write) + "-v", "${local.root_dir}:/work:A:c,dotsrch", # Share work directory (All Perms) + "-e2dsa", # Enables general file indexing" + "--re-maxage", "900", # Rescan filesystem for changes every SEC + "--see-dots", # Show dotfiles by default if user has correct permissions on volume + "--xff-src=lan", # List of trusted reverse-proxy CIDRs (comma-separated) or `lan` for private IPs. + "--rproxy", "1", # Which ip to associate clients with, index of X-FWD IP. ] } ``` diff --git a/registry/djarbz/modules/copyparty/run.sh b/registry/djarbz/modules/copyparty/run.sh index 46451f878..a138f5402 100755 --- a/registry/djarbz/modules/copyparty/run.sh +++ b/registry/djarbz/modules/copyparty/run.sh @@ -63,14 +63,14 @@ DOWNLOAD_URL="https://github.com/9001/copyparty/releases/download/$${RELEASE_TO_ printf "⏬ Downloading copyparty-sfx.py...\n" if ! curl -fsSL -o /tmp/copyparty-sfx.py "$${DOWNLOAD_URL}/copyparty-sfx.py"; then - printf "❌ Failed to download copyparty-sfx.py.\n" - exit 1 + printf "❌ Failed to download copyparty-sfx.py.\n" + exit 1 fi printf "⏬ Downloading helptext.html...\n" if ! curl -fsSL -o /tmp/helptext.html "$${DOWNLOAD_URL}/helptext.html"; then - # This is not a fatal error, just a warning. - printf "⚠️ Could not download helptext.html. The application will still work.\n" + # This is not a fatal error, just a warning. + printf "⚠️ Could not download helptext.html. The application will still work.\n" fi chmod +x /tmp/copyparty-sfx.py @@ -81,7 +81,7 @@ printf "🥳 Installation complete!\n\n" # Build a clean, quoted string of the command for logging purposes only. log_command="python3 /tmp/copyparty-sfx.py -p '$${PORT}'" for arg in "$${ARGUMENTS[@]}"; do - # printf "DEBUG: ARG [$${arg}]\n" + # printf "DEBUG: ARG [$${arg}]\n" log_command+=" '$${arg}'" done diff --git a/registry/djarbz/repo_setup.md b/registry/djarbz/repo_setup.md index a8ec422d5..fda6ef003 100644 --- a/registry/djarbz/repo_setup.md +++ b/registry/djarbz/repo_setup.md @@ -11,10 +11,11 @@ nvm install node npm install ``` -## Install Bun +## Install NPM Tooling ```bash npm install -g bun +npm install -g prettier ``` ## Install Terraform @@ -35,3 +36,13 @@ sudo apt-get install -y terraform ## Install Extenstions - hashicorp.terraform + +## Testing + +```bash +bun run fmt +npx prettier . --write +# From registry namespace +terraform init -upgrade +terraform test -verbose +``` From 3e5bf2052e70376124e95ddca493a0a58d36ccfa Mon Sep 17 00:00:00 2001 From: default Date: Fri, 17 Oct 2025 19:06:26 -0500 Subject: [PATCH 3/6] Fix typo --- registry/djarbz/repo_setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/djarbz/repo_setup.md b/registry/djarbz/repo_setup.md index fda6ef003..17ca2998d 100644 --- a/registry/djarbz/repo_setup.md +++ b/registry/djarbz/repo_setup.md @@ -33,7 +33,7 @@ sudo apt update sudo apt-get install -y terraform ``` -## Install Extenstions +## Install Extensions - hashicorp.terraform From b9fe5f50684e2619f923456e9e39a99e6919165b Mon Sep 17 00:00:00 2001 From: default Date: Wed, 22 Oct 2025 09:55:24 -0500 Subject: [PATCH 4/6] Remove Repo_Setup Notes --- registry/djarbz/repo_setup.md | 48 ----------------------------------- 1 file changed, 48 deletions(-) delete mode 100644 registry/djarbz/repo_setup.md diff --git a/registry/djarbz/repo_setup.md b/registry/djarbz/repo_setup.md deleted file mode 100644 index 17ca2998d..000000000 --- a/registry/djarbz/repo_setup.md +++ /dev/null @@ -1,48 +0,0 @@ -# Notes on Environment Setup - -## Install Node - -```bash -curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash -export NVM_DIR="$HOME/.nvm" -[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" -[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" -nvm install node -npm install -``` - -## Install NPM Tooling - -```bash -npm install -g bun -npm install -g prettier -``` - -## Install Terraform - -```bash -sudo apt-get update && sudo apt-get install -y gnupg software-properties-common -curl -fsSL https://apt.releases.hashicorp.com/gpg \ - | gpg --dearmor \ - | sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg > /dev/null -gpg --no-default-keyring \ - --keyring /usr/share/keyrings/hashicorp-archive-keyring.gpg \ - --fingerprint -echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(grep -oP '(?<=UBUNTU_CODENAME=).*' /etc/os-release || lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list -sudo apt update -sudo apt-get install -y terraform -``` - -## Install Extensions - -- hashicorp.terraform - -## Testing - -```bash -bun run fmt -npx prettier . --write -# From registry namespace -terraform init -upgrade -terraform test -verbose -``` From f7c63d65bba66d66f191d40d8efd4b13b8c7a3a2 Mon Sep 17 00:00:00 2001 From: default Date: Wed, 22 Oct 2025 09:56:49 -0500 Subject: [PATCH 5/6] Update Version --- registry/djarbz/modules/copyparty/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/registry/djarbz/modules/copyparty/README.md b/registry/djarbz/modules/copyparty/README.md index 70119d598..fdd3ad56e 100644 --- a/registry/djarbz/modules/copyparty/README.md +++ b/registry/djarbz/modules/copyparty/README.md @@ -17,7 +17,7 @@ This module installs Copyparty, an alternative to Filebrowser. module "copyparty" { count = data.coder_workspace.me.start_count source = "registry.coder.com/djarbz/copyparty/coder" - version = "0.1.0" + version = "1.0.0" } ``` @@ -35,7 +35,7 @@ Some basic command line options: module "copyparty" { count = data.coder_workspace.me.start_count source = "registry.coder.com/djarbz/copyparty/coder" - version = "0.1.0" + version = "1.0.0" agent_id = coder_agent.example.id arguments = [ "-v", "/home/coder/:/home:r", # Share home directory (read-only) @@ -51,7 +51,7 @@ module "copyparty" { module "copyparty" { count = data.coder_workspace.me.start_count source = "registry.coder.com/djarbz/copyparty/coder" - version = "0.1.0" + version = "1.0.0" agent_id = coder_agent.example.id subdomain = true arguments = [ From d717f6ee0b7ee1d155b16a9d866ecbf2d3d0ae74 Mon Sep 17 00:00:00 2001 From: default Date: Wed, 22 Oct 2025 09:57:01 -0500 Subject: [PATCH 6/6] Reference local icon --- registry/djarbz/modules/copyparty/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/djarbz/modules/copyparty/main.tf b/registry/djarbz/modules/copyparty/main.tf index 3a975c947..822387c1e 100644 --- a/registry/djarbz/modules/copyparty/main.tf +++ b/registry/djarbz/modules/copyparty/main.tf @@ -11,7 +11,7 @@ terraform { locals { # A built-in icon like "/icon/code.svg" or a full URL of icon - icon_url = "https://raw.githubusercontent.com/9001/copyparty/refs/heads/hovudstraum/docs/logo.svg" + icon_url = "/icon/copyparty.svg" # a map of all possible values # options = { # "Option 1" = {