diff --git a/public/svgs/altcha.svg b/public/svgs/altcha.svg new file mode 100644 index 0000000000..007f96bab1 --- /dev/null +++ b/public/svgs/altcha.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/templates/compose/altcha.yaml b/templates/compose/altcha.yaml new file mode 100644 index 0000000000..6ae8a44ac7 --- /dev/null +++ b/templates/compose/altcha.yaml @@ -0,0 +1,25 @@ +# documentation: https://altcha.org/docs/v2/sentinel/install/docker +# slogan: ALTCHA Sentinel protects websites and APIs from spam, bots, and abuse. +# category: security +# tags: captcha, anti-spam, bot protection, privacy, security +# logo: svgs/altcha.svg +# port: 8080 + +services: + altcha: + image: 'ghcr.io/altcha-org/sentinel:${ALTCHA_VERSION:-latest}' + environment: + - SERVICE_URL_ALTCHA_8080 + volumes: + - altcha-data:/data + healthcheck: + test: + - CMD-SHELL + - "grep -q ':1F90 ' /proc/net/tcp /proc/net/tcp6" + interval: 10s + timeout: 5s + retries: 10 + start_period: 10s + +volumes: + altcha-data: diff --git a/templates/service-templates-latest.json b/templates/service-templates-latest.json index 3098e52699..8d8a1c607c 100644 --- a/templates/service-templates-latest.json +++ b/templates/service-templates-latest.json @@ -50,6 +50,23 @@ "template_last_updated_at": "2025-08-18T18:12:16+02:00", "port": "3010" }, + "altcha": { + "documentation": "https://altcha.org/docs/v2/sentinel/install/docker?utm_source=coolify.io", + "slogan": "ALTCHA Sentinel protects websites and APIs from spam, bots, and abuse.", + "compose": "c2VydmljZXM6CiAgYWx0Y2hhOgogICAgaW1hZ2U6ICdnaGNyLmlvL2FsdGNoYS1vcmcvc2VudGluZWw6JHtBTFRDSEFfVkVSU0lPTjotbGF0ZXN0fScKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfVVJMX0FMVENIQV84MDgwCiAgICB2b2x1bWVzOgogICAgICAtICdhbHRjaGEtZGF0YTovZGF0YScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAiZ3JlcCAtcSAnOjFGOTAgJyAvcHJvYy9uZXQvdGNwIC9wcm9jL25ldC90Y3A2IgogICAgICBpbnRlcnZhbDogMTBzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDEwCiAgICAgIHN0YXJ0X3BlcmlvZDogMTBzCnZvbHVtZXM6CiAgYWx0Y2hhLWRhdGE6IG51bGwK", + "tags": [ + "captcha", + "anti-spam", + "bot protection", + "privacy", + "security" + ], + "category": "security", + "logo": "svgs/altcha.svg", + "minversion": "0.0.0", + "template_last_updated_at": null, + "port": "8080" + }, "alexandrie": { "documentation": "https://github.com/Smaug6739/Alexandrie/tree/main/docs?utm_source=coolify.io", "slogan": "A powerful Markdown workspace designed for speed, clarity, and creativity.", diff --git a/templates/service-templates.json b/templates/service-templates.json index 1574f77685..ceb550244f 100644 --- a/templates/service-templates.json +++ b/templates/service-templates.json @@ -50,6 +50,23 @@ "template_last_updated_at": "2025-08-18T18:12:16+02:00", "port": "3010" }, + "altcha": { + "documentation": "https://altcha.org/docs/v2/sentinel/install/docker?utm_source=coolify.io", + "slogan": "ALTCHA Sentinel protects websites and APIs from spam, bots, and abuse.", + "compose": "c2VydmljZXM6CiAgYWx0Y2hhOgogICAgaW1hZ2U6ICdnaGNyLmlvL2FsdGNoYS1vcmcvc2VudGluZWw6JHtBTFRDSEFfVkVSU0lPTjotbGF0ZXN0fScKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9BTFRDSEFfODA4MAogICAgdm9sdW1lczoKICAgICAgLSAnYWx0Y2hhLWRhdGE6L2RhdGEnCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gImdyZXAgLXEgJzoxRjkwICcgL3Byb2MvbmV0L3RjcCAvcHJvYy9uZXQvdGNwNiIKICAgICAgaW50ZXJ2YWw6IDEwcwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiAxMAogICAgICBzdGFydF9wZXJpb2Q6IDEwcwp2b2x1bWVzOgogIGFsdGNoYS1kYXRhOiBudWxsCg==", + "tags": [ + "captcha", + "anti-spam", + "bot protection", + "privacy", + "security" + ], + "category": "security", + "logo": "svgs/altcha.svg", + "minversion": "0.0.0", + "template_last_updated_at": null, + "port": "8080" + }, "alexandrie": { "documentation": "https://github.com/Smaug6739/Alexandrie/tree/main/docs?utm_source=coolify.io", "slogan": "A powerful Markdown workspace designed for speed, clarity, and creativity.", diff --git a/tests/Unit/AltchaServiceTemplateTest.php b/tests/Unit/AltchaServiceTemplateTest.php new file mode 100644 index 0000000000..a13c81cde5 --- /dev/null +++ b/tests/Unit/AltchaServiceTemplateTest.php @@ -0,0 +1,40 @@ +toBeFile(); + + $compose = file_get_contents($templatePath); + + expect($compose) + ->toContain('ghcr.io/altcha-org/sentinel:${ALTCHA_VERSION:-latest}') + ->toContain('SERVICE_URL_ALTCHA_8080') + ->toContain('altcha-data:/data') + ->toContain("grep -q ':1F90 ' /proc/net/tcp /proc/net/tcp6") + ->toContain("volumes:\n altcha-data:") + ->not->toContain('busybox wget'); + + foreach (['service-templates.json', 'service-templates-latest.json'] as $templateFile) { + $templates = json_decode( + file_get_contents(__DIR__."/../../templates/{$templateFile}"), + associative: true, + flags: JSON_THROW_ON_ERROR, + ); + + expect($templates)->toHaveKey('altcha'); + expect($templates['altcha']['port'] ?? null)->toBe('8080'); + expect($templates['altcha']['logo'] ?? null)->toBe('svgs/altcha.svg'); + expect($templates['altcha']['category'] ?? null)->toBe('security'); + + $generatedCompose = base64_decode($templates['altcha']['compose'], strict: true); + + expect($generatedCompose) + ->toContain('ghcr.io/altcha-org/sentinel:${ALTCHA_VERSION:-latest}') + ->toContain("grep -q ':1F90 ' /proc/net/tcp /proc/net/tcp6") + ->toContain("volumes:\n altcha-data:") + ->toContain($templateFile === 'service-templates.json' + ? 'SERVICE_FQDN_ALTCHA_8080' + : 'SERVICE_URL_ALTCHA_8080'); + } +});