summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Readme.md3
-rw-r--r--bin/compile10
-rw-r--r--bin/iac4
-rw-r--r--composer.json28
-rw-r--r--composer.lock1087
-rw-r--r--index.php6
-rw-r--r--src/Command/RunCommand.php46
-rw-r--r--src/IAC.php25
-rw-r--r--src/Module/AptModule.php48
-rw-r--r--src/Module/ModuleInterface.php10
-rw-r--r--src/Module/State.php9
-rw-r--r--src/Task.php27
13 files changed, 1305 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9c7e18a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+/vendor/
+iac.phar
diff --git a/Readme.md b/Readme.md
new file mode 100644
index 0000000..884587d
--- /dev/null
+++ b/Readme.md
@@ -0,0 +1,3 @@
+# References
+
+- https://medium.com/@tfidry/create-and-deploy-secure-phars-c5572f10b4dd
diff --git a/bin/compile b/bin/compile
new file mode 100644
index 0000000..a36967e
--- /dev/null
+++ b/bin/compile
@@ -0,0 +1,10 @@
+#!/usr/bin/env php
+<?php
+
+unlink(getcwd() . '/iac.phar');
+#chdir(dirname(__DIR__));
+#exec('composer install --no-dev');
+
+$phar = new Phar('iac.phar');
+$phar->setStub(Phar::createDefaultStub());
+$phar->buildFromDirectory(dirname(__DIR__), '/(src|vendor|index\.php)/');
diff --git a/bin/iac b/bin/iac
new file mode 100644
index 0000000..b645010
--- /dev/null
+++ b/bin/iac
@@ -0,0 +1,4 @@
+#!/usr/bin/env php
+<?php
+
+require dirname(__DIR__) . '/index.php';
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..f1b9ba7
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,28 @@
+{
+ "name": "dweipert/php-iac",
+ "type": "library",
+ "license": "AGPL-3.0-only",
+ "authors": [
+ {
+ "name": "Daniel Weipert",
+ "email": "code@drogueronin.de"
+ }
+ ],
+ "require": {
+ "php": "^8.0",
+ "symfony/console": "^5.2",
+ "petrknap/php-singleton": "^1.0",
+ "phpseclib/phpseclib": "^3.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "PHPIAC\\": "src"
+ }
+ },
+ "bin": [
+ "bin/iac"
+ ],
+ "scripts": {
+ "compile": "@php -dphar.readonly=0 bin/compile"
+ }
+}
diff --git a/composer.lock b/composer.lock
new file mode 100644
index 0000000..4536647
--- /dev/null
+++ b/composer.lock
@@ -0,0 +1,1087 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
+ "This file is @generated automatically"
+ ],
+ "content-hash": "aa317bad874c3a475803c6d7057df553",
+ "packages": [
+ {
+ "name": "paragonie/constant_time_encoding",
+ "version": "v2.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/paragonie/constant_time_encoding.git",
+ "reference": "f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c",
+ "reference": "f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7|^8"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6|^7|^8|^9",
+ "vimeo/psalm": "^1|^2|^3|^4"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "ParagonIE\\ConstantTime\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Paragon Initiative Enterprises",
+ "email": "security@paragonie.com",
+ "homepage": "https://paragonie.com",
+ "role": "Maintainer"
+ },
+ {
+ "name": "Steve 'Sc00bz' Thomas",
+ "email": "steve@tobtu.com",
+ "homepage": "https://www.tobtu.com",
+ "role": "Original Developer"
+ }
+ ],
+ "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)",
+ "keywords": [
+ "base16",
+ "base32",
+ "base32_decode",
+ "base32_encode",
+ "base64",
+ "base64_decode",
+ "base64_encode",
+ "bin2hex",
+ "encoding",
+ "hex",
+ "hex2bin",
+ "rfc4648"
+ ],
+ "support": {
+ "email": "info@paragonie.com",
+ "issues": "https://github.com/paragonie/constant_time_encoding/issues",
+ "source": "https://github.com/paragonie/constant_time_encoding"
+ },
+ "time": "2020-12-06T15:14:20+00:00"
+ },
+ {
+ "name": "paragonie/random_compat",
+ "version": "v9.99.100",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/paragonie/random_compat.git",
+ "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a",
+ "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">= 7"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "4.*|5.*",
+ "vimeo/psalm": "^1"
+ },
+ "suggest": {
+ "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
+ },
+ "type": "library",
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Paragon Initiative Enterprises",
+ "email": "security@paragonie.com",
+ "homepage": "https://paragonie.com"
+ }
+ ],
+ "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
+ "keywords": [
+ "csprng",
+ "polyfill",
+ "pseudorandom",
+ "random"
+ ],
+ "support": {
+ "email": "info@paragonie.com",
+ "issues": "https://github.com/paragonie/random_compat/issues",
+ "source": "https://github.com/paragonie/random_compat"
+ },
+ "time": "2020-10-15T08:29:30+00:00"
+ },
+ {
+ "name": "petrknap/php-singleton",
+ "version": "v1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/petrknap/php-singleton.git",
+ "reference": "dec131d0d6c72dd76b5a5c7940f04f14f5df7a20"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/petrknap/php-singleton/zipball/dec131d0d6c72dd76b5a5c7940f04f14f5df7a20",
+ "reference": "dec131d0d6c72dd76b5a5c7940f04f14f5df7a20",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.4"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "4.*"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "PetrKnap\\Php\\Singleton\\": "src/Singleton"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Petr Knap",
+ "email": "dev@petrknap.cz",
+ "homepage": "http://petrknap.cz"
+ }
+ ],
+ "description": "Singleton pattern for PHP",
+ "homepage": "https://github.com/petrknap/php-singleton",
+ "support": {
+ "issues": "https://github.com/petrknap/php-singleton/issues",
+ "source": "https://github.com/petrknap/php-singleton/tree/master"
+ },
+ "time": "2016-09-22T07:59:18+00:00"
+ },
+ {
+ "name": "phpseclib/phpseclib",
+ "version": "3.0.7",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpseclib/phpseclib.git",
+ "reference": "d369510df0ebd5e1a5d0fe3d4d23c55fa87a403d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/d369510df0ebd5e1a5d0fe3d4d23c55fa87a403d",
+ "reference": "d369510df0ebd5e1a5d0fe3d4d23c55fa87a403d",
+ "shasum": ""
+ },
+ "require": {
+ "paragonie/constant_time_encoding": "^1|^2",
+ "paragonie/random_compat": "^1.4|^2.0|^9.99.99",
+ "php": ">=5.6.1"
+ },
+ "require-dev": {
+ "phing/phing": "~2.7",
+ "phpunit/phpunit": "^5.7|^6.0|^9.4",
+ "squizlabs/php_codesniffer": "~2.0"
+ },
+ "suggest": {
+ "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.",
+ "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.",
+ "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.",
+ "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations."
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "phpseclib/bootstrap.php"
+ ],
+ "psr-4": {
+ "phpseclib3\\": "phpseclib/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jim Wigginton",
+ "email": "terrafrost@php.net",
+ "role": "Lead Developer"
+ },
+ {
+ "name": "Patrick Monnerat",
+ "email": "pm@datasphere.ch",
+ "role": "Developer"
+ },
+ {
+ "name": "Andreas Fischer",
+ "email": "bantu@phpbb.com",
+ "role": "Developer"
+ },
+ {
+ "name": "Hans-Jürgen Petrich",
+ "email": "petrich@tronic-media.com",
+ "role": "Developer"
+ },
+ {
+ "name": "Graham Campbell",
+ "email": "graham@alt-three.com",
+ "role": "Developer"
+ }
+ ],
+ "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.",
+ "homepage": "http://phpseclib.sourceforge.net",
+ "keywords": [
+ "BigInteger",
+ "aes",
+ "asn.1",
+ "asn1",
+ "blowfish",
+ "crypto",
+ "cryptography",
+ "encryption",
+ "rsa",
+ "security",
+ "sftp",
+ "signature",
+ "signing",
+ "ssh",
+ "twofish",
+ "x.509",
+ "x509"
+ ],
+ "support": {
+ "issues": "https://github.com/phpseclib/phpseclib/issues",
+ "source": "https://github.com/phpseclib/phpseclib/tree/3.0.7"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/terrafrost",
+ "type": "github"
+ },
+ {
+ "url": "https://www.patreon.com/phpseclib",
+ "type": "patreon"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2021-04-06T14:00:11+00:00"
+ },
+ {
+ "name": "psr/container",
+ "version": "1.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/container.git",
+ "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf",
+ "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Psr\\Container\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common Container Interface (PHP FIG PSR-11)",
+ "homepage": "https://github.com/php-fig/container",
+ "keywords": [
+ "PSR-11",
+ "container",
+ "container-interface",
+ "container-interop",
+ "psr"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/container/issues",
+ "source": "https://github.com/php-fig/container/tree/1.1.1"
+ },
+ "time": "2021-03-05T17:36:06+00:00"
+ },
+ {
+ "name": "symfony/console",
+ "version": "v5.2.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/console.git",
+ "reference": "35f039df40a3b335ebf310f244cb242b3a83ac8d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/console/zipball/35f039df40a3b335ebf310f244cb242b3a83ac8d",
+ "reference": "35f039df40a3b335ebf310f244cb242b3a83ac8d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2.5",
+ "symfony/polyfill-mbstring": "~1.0",
+ "symfony/polyfill-php73": "^1.8",
+ "symfony/polyfill-php80": "^1.15",
+ "symfony/service-contracts": "^1.1|^2",
+ "symfony/string": "^5.1"
+ },
+ "conflict": {
+ "symfony/dependency-injection": "<4.4",
+ "symfony/dotenv": "<5.1",
+ "symfony/event-dispatcher": "<4.4",
+ "symfony/lock": "<4.4",
+ "symfony/process": "<4.4"
+ },
+ "provide": {
+ "psr/log-implementation": "1.0"
+ },
+ "require-dev": {
+ "psr/log": "~1.0",
+ "symfony/config": "^4.4|^5.0",
+ "symfony/dependency-injection": "^4.4|^5.0",
+ "symfony/event-dispatcher": "^4.4|^5.0",
+ "symfony/lock": "^4.4|^5.0",
+ "symfony/process": "^4.4|^5.0",
+ "symfony/var-dumper": "^4.4|^5.0"
+ },
+ "suggest": {
+ "psr/log": "For using the console logger",
+ "symfony/event-dispatcher": "",
+ "symfony/lock": "",
+ "symfony/process": ""
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Console\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Eases the creation of beautiful and testable command line interfaces",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "cli",
+ "command line",
+ "console",
+ "terminal"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/console/tree/v5.2.6"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2021-03-28T09:42:18+00:00"
+ },
+ {
+ "name": "symfony/polyfill-ctype",
+ "version": "v1.22.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-ctype.git",
+ "reference": "c6c942b1ac76c82448322025e084cadc56048b4e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e",
+ "reference": "c6c942b1ac76c82448322025e084cadc56048b4e",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "suggest": {
+ "ext-ctype": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.22-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Ctype\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Gert de Pagter",
+ "email": "BackEndTea@gmail.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for ctype functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "ctype",
+ "polyfill",
+ "portable"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.1"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2021-01-07T16:49:33+00:00"
+ },
+ {
+ "name": "symfony/polyfill-intl-grapheme",
+ "version": "v1.22.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-intl-grapheme.git",
+ "reference": "5601e09b69f26c1828b13b6bb87cb07cddba3170"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/5601e09b69f26c1828b13b6bb87cb07cddba3170",
+ "reference": "5601e09b69f26c1828b13b6bb87cb07cddba3170",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "suggest": {
+ "ext-intl": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.22-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Intl\\Grapheme\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for intl's grapheme_* functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "grapheme",
+ "intl",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.22.1"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2021-01-22T09:19:47+00:00"
+ },
+ {
+ "name": "symfony/polyfill-intl-normalizer",
+ "version": "v1.22.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
+ "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/43a0283138253ed1d48d352ab6d0bdb3f809f248",
+ "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "suggest": {
+ "ext-intl": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.22-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Intl\\Normalizer\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ],
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for intl's Normalizer class and related functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "intl",
+ "normalizer",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.22.1"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2021-01-22T09:19:47+00:00"
+ },
+ {
+ "name": "symfony/polyfill-mbstring",
+ "version": "v1.22.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-mbstring.git",
+ "reference": "5232de97ee3b75b0360528dae24e73db49566ab1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/5232de97ee3b75b0360528dae24e73db49566ab1",
+ "reference": "5232de97ee3b75b0360528dae24e73db49566ab1",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "suggest": {
+ "ext-mbstring": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.22-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Mbstring\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for the Mbstring extension",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "mbstring",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.22.1"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2021-01-22T09:19:47+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php73",
+ "version": "v1.22.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php73.git",
+ "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/a678b42e92f86eca04b7fa4c0f6f19d097fb69e2",
+ "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.22-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Php73\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ],
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php73/tree/v1.22.1"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2021-01-07T16:49:33+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php80",
+ "version": "v1.22.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php80.git",
+ "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dc3063ba22c2a1fd2f45ed856374d79114998f91",
+ "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.22-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Php80\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ],
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ion Bazan",
+ "email": "ion.bazan@gmail.com"
+ },
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php80/tree/v1.22.1"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2021-01-07T16:49:33+00:00"
+ },
+ {
+ "name": "symfony/service-contracts",
+ "version": "v2.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/service-contracts.git",
+ "reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d15da7ba4957ffb8f1747218be9e1a121fd298a1",
+ "reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2.5",
+ "psr/container": "^1.0"
+ },
+ "suggest": {
+ "symfony/service-implementation": ""
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.2-dev"
+ },
+ "thanks": {
+ "name": "symfony/contracts",
+ "url": "https://github.com/symfony/contracts"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Contracts\\Service\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Generic abstractions related to writing services",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "abstractions",
+ "contracts",
+ "decoupling",
+ "interfaces",
+ "interoperability",
+ "standards"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/service-contracts/tree/master"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2020-09-07T11:33:47+00:00"
+ },
+ {
+ "name": "symfony/string",
+ "version": "v5.2.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/string.git",
+ "reference": "ad0bd91bce2054103f5eaa18ebeba8d3bc2a0572"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/string/zipball/ad0bd91bce2054103f5eaa18ebeba8d3bc2a0572",
+ "reference": "ad0bd91bce2054103f5eaa18ebeba8d3bc2a0572",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2.5",
+ "symfony/polyfill-ctype": "~1.8",
+ "symfony/polyfill-intl-grapheme": "~1.0",
+ "symfony/polyfill-intl-normalizer": "~1.0",
+ "symfony/polyfill-mbstring": "~1.0",
+ "symfony/polyfill-php80": "~1.15"
+ },
+ "require-dev": {
+ "symfony/error-handler": "^4.4|^5.0",
+ "symfony/http-client": "^4.4|^5.0",
+ "symfony/translation-contracts": "^1.1|^2",
+ "symfony/var-exporter": "^4.4|^5.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\String\\": ""
+ },
+ "files": [
+ "Resources/functions.php"
+ ],
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "grapheme",
+ "i18n",
+ "string",
+ "unicode",
+ "utf-8",
+ "utf8"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/string/tree/v5.2.6"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2021-03-17T17:12:15+00:00"
+ }
+ ],
+ "packages-dev": [],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": [],
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": {
+ "php": "^8.0"
+ },
+ "platform-dev": [],
+ "plugin-api-version": "2.0.0"
+}
diff --git a/index.php b/index.php
new file mode 100644
index 0000000..0585c36
--- /dev/null
+++ b/index.php
@@ -0,0 +1,6 @@
+#!/usr/bin/env php
+<?php
+
+require __DIR__ . '/vendor/autoload.php';
+
+\PHPIAC\IAC::getInstance();
diff --git a/src/Command/RunCommand.php b/src/Command/RunCommand.php
new file mode 100644
index 0000000..048e94c
--- /dev/null
+++ b/src/Command/RunCommand.php
@@ -0,0 +1,46 @@
+<?php
+
+namespace PHPIAC\Command;
+
+use PHPIAC\Task;
+use phpseclib3\Crypt\PublicKeyLoader;
+use phpseclib3\Net\SSH2;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class RunCommand extends Command
+{
+ protected static $defaultName = 'run';
+
+ protected function configure()
+ {}
+
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $cwd = getcwd();
+ $config = include $cwd . '/config.php';
+
+ global $ssh;
+ $ssh = new SSH2($config['host']);
+ if (! $ssh->login($config['user'], PublicKeyLoader::load(file_get_contents($config['private_key_file'])))) {
+ throw new \Exception('Login failed');
+ }
+
+ $commands = [];
+ foreach ($config['tasks'] as $task) {
+ /**@var Task $task*/
+ if (! $task->module->checkState()) {
+ $output->writeln('Adding commands from ' . get_class($task->module));
+ array_push($commands, ...$task->module->getCommands());
+ }
+ else {
+ $output->writeln('Skipping commands from ' . get_class($task->module));
+ }
+ }
+
+ $ssh->exec(implode(PHP_EOL, $commands));
+
+ return Command::SUCCESS;
+ }
+}
diff --git a/src/IAC.php b/src/IAC.php
new file mode 100644
index 0000000..c4e476d
--- /dev/null
+++ b/src/IAC.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace PHPIAC;
+
+use PetrKnap\Php\Singleton\SingletonTrait;
+use PHPIAC\Command\RunCommand;
+use Symfony\Component\Console\Application;
+
+class IAC
+{
+ use SingletonTrait;
+
+ public function __construct()
+ {
+ $application = new Application();
+
+ $defaultCommand = new RunCommand();
+ $application->add($defaultCommand);
+ $application->setDefaultCommand($defaultCommand->getName());
+
+ # ... other commands here
+
+ $application->run();
+ }
+}
diff --git a/src/Module/AptModule.php b/src/Module/AptModule.php
new file mode 100644
index 0000000..ff4cb95
--- /dev/null
+++ b/src/Module/AptModule.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace PHPIAC\Module;
+
+use phpseclib3\Net\SSH2;
+
+class AptModule implements ModuleInterface
+{
+ public function __construct(
+ private string $package,
+ private string $state = State::PRESENT
+ ) {}
+
+ public function checkState(): bool
+ {
+ global $ssh;
+ /**@var SSH2 $ssh*/
+ $ssh->enablePTY();
+ $ssh->exec("which $this->package");
+
+ if ($this->state === State::PRESENT) {
+ $state = ! empty($ssh->read());
+ }
+ else if ($this->state === State::ABSENT) {
+ $state = empty($ssh->read());
+ }
+
+ $ssh->disablePTY();
+
+ return $state;
+ }
+
+ public function getCommands(): array
+ {
+ if ($this->state === State::PRESENT) {
+ return [
+ "sudo apt install -y $this->package",
+ ];
+ }
+ else if ($this->state === State::ABSENT) {
+ return [
+ "sudo apt remove -y $this->package",
+ ];
+ }
+
+ return [];
+ }
+}
diff --git a/src/Module/ModuleInterface.php b/src/Module/ModuleInterface.php
new file mode 100644
index 0000000..2963b5f
--- /dev/null
+++ b/src/Module/ModuleInterface.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace PHPIAC\Module;
+
+interface ModuleInterface
+{
+ public function checkState(): bool;
+
+ public function getCommands(): array;
+}
diff --git a/src/Module/State.php b/src/Module/State.php
new file mode 100644
index 0000000..c7f7af9
--- /dev/null
+++ b/src/Module/State.php
@@ -0,0 +1,9 @@
+<?php
+
+namespace PHPIAC\Module;
+
+class State
+{
+ public const PRESENT = 'present';
+ public const ABSENT = 'absent';
+}
diff --git a/src/Task.php b/src/Task.php
new file mode 100644
index 0000000..598f55c
--- /dev/null
+++ b/src/Task.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace PHPIAC;
+
+use PHPIAC\Module\ModuleInterface;
+
+class Task
+{
+ public function __construct(
+ public ModuleInterface $module,
+ public array $vars,
+ ) {}
+
+ public function setModule(ModuleInterface $module): self
+ {
+ $this->module = $module;
+
+ return $this;
+ }
+
+ public function setVars(array $vars): self
+ {
+ $this->vars = $vars;
+
+ return $this;
+ }
+}