kitsune-kit 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +117 -2
  3. data/CONTRIBUTING.md +83 -0
  4. data/README.md +108 -136
  5. data/SECURITY.md +25 -0
  6. data/bin/kit +4 -1
  7. data/docs/architecture/decisions/0001-product-boundary.md +23 -0
  8. data/docs/architecture/decisions/0002-core-and-interfaces.md +23 -0
  9. data/docs/architecture/decisions/0003-configuration-state-and-secrets.md +23 -0
  10. data/docs/architecture/decisions/0004-supported-platforms.md +19 -0
  11. data/docs/architecture/decisions/0005-operation-semantics.md +19 -0
  12. data/docs/architecture/decisions/0006-tui-backend.md +21 -0
  13. data/docs/architecture/provider-adapters.md +49 -0
  14. data/docs/architecture.md +89 -0
  15. data/docs/commands.md +210 -0
  16. data/docs/configuration.md +210 -0
  17. data/docs/getting-started.md +133 -0
  18. data/docs/providers/digitalocean.md +52 -0
  19. data/docs/releasing.md +43 -0
  20. data/docs/roadmap.md +46 -0
  21. data/docs/security-audit.md +130 -0
  22. data/docs/security.md +116 -0
  23. data/docs/services/postgres.md +78 -0
  24. data/docs/services/redis.md +53 -0
  25. data/docs/testing.md +200 -0
  26. data/docs/troubleshooting.md +123 -0
  27. data/docs/tui.md +57 -0
  28. data/lib/kitsune/kit/adapters/confirming_host_key_verifier.rb +42 -0
  29. data/lib/kitsune/kit/adapters/digitalocean_provider.rb +217 -0
  30. data/lib/kitsune/kit/adapters/fake_clock.rb +34 -0
  31. data/lib/kitsune/kit/adapters/fake_provider.rb +107 -0
  32. data/lib/kitsune/kit/adapters/fake_reporter.rb +34 -0
  33. data/lib/kitsune/kit/adapters/fake_secret_store.rb +35 -0
  34. data/lib/kitsune/kit/adapters/fake_state_store.rb +91 -0
  35. data/lib/kitsune/kit/adapters/fake_transport.rb +56 -0
  36. data/lib/kitsune/kit/adapters/net_ssh_transport.rb +155 -0
  37. data/lib/kitsune/kit/adapters/provider.rb +34 -0
  38. data/lib/kitsune/kit/adapters/transport.rb +22 -0
  39. data/lib/kitsune/kit/adapters/transport_factory.rb +116 -0
  40. data/lib/kitsune/kit/application.rb +170 -0
  41. data/lib/kitsune/kit/cancellation.rb +21 -0
  42. data/lib/kitsune/kit/cli.rb +802 -64
  43. data/lib/kitsune/kit/clock.rb +11 -0
  44. data/lib/kitsune/kit/configuration.rb +493 -0
  45. data/lib/kitsune/kit/errors.rb +98 -0
  46. data/lib/kitsune/kit/events.rb +55 -0
  47. data/lib/kitsune/kit/operations/ensure_dns_records.rb +165 -0
  48. data/lib/kitsune/kit/operations/ensure_server.rb +135 -0
  49. data/lib/kitsune/kit/operations/ensure_service.rb +285 -0
  50. data/lib/kitsune/kit/operations/remote_script.rb +214 -0
  51. data/lib/kitsune/kit/operations/service_backup.rb +71 -0
  52. data/lib/kitsune/kit/operations/service_files.rb +127 -0
  53. data/lib/kitsune/kit/operations/service_firewall.rb +190 -0
  54. data/lib/kitsune/kit/operations/service_state.rb +59 -0
  55. data/lib/kitsune/kit/plan.rb +72 -0
  56. data/lib/kitsune/kit/reporters/human.rb +89 -0
  57. data/lib/kitsune/kit/reporters/json.rb +65 -0
  58. data/lib/kitsune/kit/reporters/reporter.rb +11 -0
  59. data/lib/kitsune/kit/result.rb +28 -0
  60. data/lib/kitsune/kit/run_journal.rb +102 -0
  61. data/lib/kitsune/kit/run_logger.rb +37 -0
  62. data/lib/kitsune/kit/scripts/docker.sh +137 -0
  63. data/lib/kitsune/kit/scripts/firewall.sh +205 -0
  64. data/lib/kitsune/kit/scripts/metrics.sh +54 -0
  65. data/lib/kitsune/kit/scripts/ssh.sh +95 -0
  66. data/lib/kitsune/kit/scripts/swap.sh +86 -0
  67. data/lib/kitsune/kit/scripts/unattended.sh +81 -0
  68. data/lib/kitsune/kit/scripts/user.sh +114 -0
  69. data/lib/kitsune/kit/secret_filter.rb +54 -0
  70. data/lib/kitsune/kit/secret_store.rb +32 -0
  71. data/lib/kitsune/kit/secret_stores/store.rb +12 -0
  72. data/lib/kitsune/kit/service_compose.rb +72 -0
  73. data/lib/kitsune/kit/state_store.rb +158 -0
  74. data/lib/kitsune/kit/state_stores/store.rb +15 -0
  75. data/lib/kitsune/kit/tui/actions.rb +72 -0
  76. data/lib/kitsune/kit/tui/application.rb +35 -0
  77. data/lib/kitsune/kit/tui/controller.rb +162 -0
  78. data/lib/kitsune/kit/tui/renderer.rb +134 -0
  79. data/lib/kitsune/kit/tui/state.rb +18 -0
  80. data/lib/kitsune/kit/tui/store.rb +88 -0
  81. data/lib/kitsune/kit/tui/terminal.rb +95 -0
  82. data/lib/kitsune/kit/version.rb +1 -1
  83. data/lib/kitsune/kit/workflows/apply_plan.rb +145 -0
  84. data/lib/kitsune/kit/workflows/base.rb +31 -0
  85. data/lib/kitsune/kit/workflows/build_plan.rb +33 -0
  86. data/lib/kitsune/kit/workflows/destroy_server.rb +84 -0
  87. data/lib/kitsune/kit/workflows/doctor.rb +225 -0
  88. data/lib/kitsune/kit/workflows/environment_selection.rb +70 -0
  89. data/lib/kitsune/kit/workflows/import_server.rb +100 -0
  90. data/lib/kitsune/kit/workflows/initialize_project.rb +121 -0
  91. data/lib/kitsune/kit/workflows/inspect_environment.rb +44 -0
  92. data/lib/kitsune/kit/workflows/rollback.rb +54 -0
  93. data/lib/kitsune/kit/workflows/support_bundle.rb +82 -0
  94. data/lib/kitsune/kit.rb +41 -2
  95. metadata +122 -79
  96. data/.rspec +0 -3
  97. data/Rakefile +0 -8
  98. data/kitsune-kit-logo.jpg +0 -0
  99. data/lib/kitsune/blueprints/.env.template +0 -31
  100. data/lib/kitsune/blueprints/docker/postgres.yml +0 -27
  101. data/lib/kitsune/blueprints/docker/redis.yml +0 -23
  102. data/lib/kitsune/blueprints/kit.env.template +0 -1
  103. data/lib/kitsune/kit/ansi_color.rb +0 -78
  104. data/lib/kitsune/kit/commands/bootstrap.rb +0 -134
  105. data/lib/kitsune/kit/commands/bootstrap_docker.rb +0 -66
  106. data/lib/kitsune/kit/commands/dns.rb +0 -112
  107. data/lib/kitsune/kit/commands/init.rb +0 -148
  108. data/lib/kitsune/kit/commands/install_docker_engine.rb +0 -146
  109. data/lib/kitsune/kit/commands/postinstall_docker.rb +0 -142
  110. data/lib/kitsune/kit/commands/provision.rb +0 -43
  111. data/lib/kitsune/kit/commands/setup_do_metrics.rb +0 -123
  112. data/lib/kitsune/kit/commands/setup_docker_prereqs.rb +0 -151
  113. data/lib/kitsune/kit/commands/setup_firewall.rb +0 -132
  114. data/lib/kitsune/kit/commands/setup_postgres_docker.rb +0 -246
  115. data/lib/kitsune/kit/commands/setup_redis_docker.rb +0 -241
  116. data/lib/kitsune/kit/commands/setup_swap.rb +0 -151
  117. data/lib/kitsune/kit/commands/setup_unattended.rb +0 -132
  118. data/lib/kitsune/kit/commands/setup_user.rb +0 -189
  119. data/lib/kitsune/kit/commands/ssh.rb +0 -46
  120. data/lib/kitsune/kit/commands/switch_env.rb +0 -42
  121. data/lib/kitsune/kit/defaults.rb +0 -91
  122. data/lib/kitsune/kit/env_loader.rb +0 -41
  123. data/lib/kitsune/kit/options_builder.rb +0 -26
  124. data/lib/kitsune/kit/provisioner.rb +0 -107
  125. data/sig/kitsune/kit.rbs +0 -6
@@ -1,142 +0,0 @@
1
- require "thor"
2
- require "net/ssh"
3
- require_relative "../defaults"
4
- require_relative "../options_builder"
5
-
6
- module Kitsune
7
- module Kit
8
- module Commands
9
- class PostinstallDocker < Thor
10
- namespace "postinstall_docker"
11
-
12
- class_option :server_ip, aliases: "-s", required: true, desc: "Server IP address or hostname"
13
- class_option :ssh_port, aliases: "-p", desc: "SSH port"
14
- class_option :ssh_key_path, aliases: "-k", desc: "Path to your private SSH key"
15
-
16
- desc "create", "Apply Docker post-install configuration (start service, add groups, create network)"
17
- def create
18
- filled_options = Kitsune::Kit::OptionsBuilder.build(
19
- options,
20
- required: [:server_ip],
21
- defaults: Kitsune::Kit::Defaults.ssh
22
- )
23
-
24
- with_ssh_connection(filled_options) do |ssh|
25
- perform_setup(ssh)
26
- end
27
- end
28
-
29
- desc "rollback", "Undo Docker post-install configuration"
30
- def rollback
31
- filled_options = Kitsune::Kit::OptionsBuilder.build(
32
- options,
33
- required: [:server_ip],
34
- defaults: Kitsune::Kit::Defaults.ssh
35
- )
36
-
37
- with_ssh_connection(filled_options) do |ssh|
38
- perform_rollback(ssh)
39
- end
40
- end
41
-
42
- no_commands do
43
- def with_ssh_connection(filled_options)
44
- server = filled_options[:server_ip]
45
- port = filled_options[:ssh_port]
46
- key = File.expand_path(filled_options[:ssh_key_path])
47
-
48
- say "🔑 Connecting as deploy@#{server}:#{port}", :green
49
- Net::SSH.start(server, "deploy", port: port, keys: [key], non_interactive: true, timeout: 5) do |ssh|
50
- yield ssh
51
- end
52
- end
53
-
54
- def perform_setup(ssh)
55
- output = ssh.exec! <<~EOH
56
- set -e
57
-
58
- sudo mkdir -p /usr/local/backups
59
- sudo chown deploy:deploy /usr/local/backups
60
-
61
- BACKUP_DIR="/usr/local/backups"
62
- SCRIPT_ID="postinstall_docker"
63
- BEFORE_FILE="${BACKUP_DIR}/${SCRIPT_ID}.before"
64
- AFTER_FILE="${BACKUP_DIR}/${SCRIPT_ID}.after"
65
-
66
- echo "✍🏻 Performing post-install Docker tasks"
67
-
68
- if [ ! -f "$AFTER_FILE" ]; then
69
- # Record state
70
- systemctl is-enabled docker &>/dev/null && echo "docker.service enabled" >> "$BEFORE_FILE" || echo "docker.service disabled" >> "$BEFORE_FILE"
71
- groups deploy | grep -q docker && echo "deploy in docker group" >> "$BEFORE_FILE" || echo "deploy not in docker group" >> "$BEFORE_FILE"
72
- sudo docker network inspect private &>/dev/null && echo "network private exists" >> "$BEFORE_FILE" || echo "network private absent" >> "$BEFORE_FILE"
73
-
74
- # Start and enable Docker
75
- sudo systemctl start docker
76
- sudo systemctl enable docker
77
- echo "🚀 Docker service started and enabled"
78
- echo "docker.service enabled" >> "$AFTER_FILE"
79
-
80
- # Add deploy to docker group
81
- sudo usermod -aG docker deploy
82
- echo "👥 Added 'deploy' to docker group"
83
- echo "added docker group" >> "$AFTER_FILE"
84
-
85
- # Create private network if missing
86
- if ! sudo docker network inspect private &>/dev/null; then
87
- sudo docker network create -d bridge private
88
- echo "🌐 Created Docker network 'private'"
89
- echo "created network private" >> "$AFTER_FILE"
90
- fi
91
-
92
- echo "✅ Post-install Docker tasks complete"
93
- else
94
- echo "🔄 Post-install tasks already applied, skipping setup"
95
- fi
96
- EOH
97
- say output
98
- say "✅ Post-install Docker setup completed", :green
99
- end
100
-
101
- def perform_rollback(ssh)
102
- output = ssh.exec! <<~EOH
103
- set -e
104
-
105
- sudo mkdir -p /usr/local/backups
106
- sudo chown deploy:deploy /usr/local/backups
107
-
108
- BACKUP_DIR="/usr/local/backups"
109
- SCRIPT_ID="postinstall_docker"
110
- BEFORE_FILE="${BACKUP_DIR}/${SCRIPT_ID}.before"
111
- AFTER_FILE="${BACKUP_DIR}/${SCRIPT_ID}.after"
112
-
113
- echo "🔄 Rolling back post-install Docker tasks..."
114
-
115
- if [ -f "$AFTER_FILE" ]; then
116
- if grep -Fxq "docker.service enabled" "$AFTER_FILE"; then
117
- sudo systemctl disable docker
118
- echo " - Docker service disabled"
119
- fi
120
- if grep -Fxq "added docker group" "$AFTER_FILE"; then
121
- sudo gpasswd -d deploy docker || true
122
- echo " - Removed 'deploy' from docker group"
123
- fi
124
- if grep -Fxq "created network private" "$AFTER_FILE"; then
125
- sudo docker network rm private || true
126
- echo " - Removed Docker network 'private'"
127
- fi
128
- sudo rm -f "$BEFORE_FILE" "$AFTER_FILE"
129
- else
130
- echo " - no marker for $SCRIPT_ID, skipping rollback"
131
- fi
132
-
133
- echo "✅ Rollback complete"
134
- EOH
135
- say output
136
- say "✅ Post-install Docker rollback completed", :green
137
- end
138
- end
139
- end
140
- end
141
- end
142
- end
@@ -1,43 +0,0 @@
1
- require "thor"
2
- require_relative "../defaults"
3
- require_relative "../provisioner"
4
- require_relative "../options_builder"
5
-
6
- module Kitsune
7
- module Kit
8
- module Commands
9
- class Provision < Thor
10
- namespace "provision"
11
-
12
- class_option :droplet_name, type: :string, aliases: "-n", desc: "Droplet name"
13
- class_option :region, type: :string, aliases: "-r", desc: "Region"
14
- class_option :size, type: :string, aliases: "-s", desc: "Size"
15
- class_option :image, type: :string, aliases: "-i", desc: "Image"
16
- class_option :tag, type: :string, aliases: "-t", desc: "Tag to filter/create"
17
- class_option :ssh_key_id, type: :string, aliases: "-k", desc: "SSH key ID"
18
-
19
- desc "create", "Create the Droplet if it doesn't exist"
20
- def create
21
- filled_options = Kitsune::Kit::OptionsBuilder.build(
22
- options,
23
- required: [:ssh_key_id],
24
- defaults: Kitsune::Kit::Defaults.infra
25
- )
26
-
27
- Provisioner.new(filled_options).create_or_show
28
- end
29
-
30
- desc "rollback", "Remove the Droplet if it exists"
31
- def rollback
32
- filled_options = Kitsune::Kit::OptionsBuilder.build(
33
- options,
34
- required: [:ssh_key_id],
35
- defaults: Kitsune::Kit::Defaults.infra
36
- )
37
-
38
- Provisioner.new(filled_options).rollback
39
- end
40
- end
41
- end
42
- end
43
- end
@@ -1,123 +0,0 @@
1
- require "thor"
2
- require "net/ssh"
3
- require_relative "../defaults"
4
- require_relative "../options_builder"
5
-
6
- module Kitsune
7
- module Kit
8
- module Commands
9
- class SetupDoMetrics < Thor
10
- namespace "setup_do_metrics"
11
-
12
- class_option :server_ip, aliases: "-s", required: true, desc: "Server IP address"
13
- class_option :ssh_port, aliases: "-p", desc: "SSH port"
14
- class_option :ssh_key_path, aliases: "-k", desc: "SSH private key path"
15
-
16
- desc "create", "Install and enable the DigitalOcean Metrics Agent"
17
- def create
18
- unless Kitsune::Kit::Defaults.metrics[:enable_do_metrics]
19
- say "⚠️ DigitalOcean Metrics Agent setup is disabled via ENABLE_DO_METRICS=false", :yellow
20
- return
21
- end
22
-
23
- filled_options = Kitsune::Kit::OptionsBuilder.build(
24
- options,
25
- required: [:server_ip],
26
- defaults: Kitsune::Kit::Defaults.ssh
27
- )
28
-
29
- with_ssh_connection(filled_options) do |ssh|
30
- install_agent(ssh)
31
- end
32
- end
33
-
34
- desc "rollback", "Uninstall the DigitalOcean Metrics Agent"
35
- def rollback
36
- filled_options = Kitsune::Kit::OptionsBuilder.build(
37
- options,
38
- required: [:server_ip],
39
- defaults: Kitsune::Kit::Defaults.ssh
40
- )
41
-
42
- with_ssh_connection(filled_options) do |ssh|
43
- uninstall_agent(ssh)
44
- end
45
- end
46
-
47
- no_commands do
48
- def with_ssh_connection(filled_options)
49
- Net::SSH.start(
50
- filled_options[:server_ip],
51
- "deploy",
52
- port: filled_options[:ssh_port],
53
- keys: [File.expand_path(filled_options[:ssh_key_path])],
54
- non_interactive: true,
55
- timeout: 5
56
- ) do |ssh|
57
- yield ssh
58
- end
59
- end
60
-
61
- def install_agent(ssh)
62
- marker = "/usr/local/backups/setup_do_metrics.after"
63
-
64
- script = <<~BASH
65
- set -e
66
- sudo mkdir -p /usr/local/backups
67
-
68
- if [ -f "#{marker}" ]; then
69
- echo "🔁 Metrics Agent already installed, skipping."
70
- exit 0
71
- fi
72
-
73
- echo "✍🏻 Installing DigitalOcean Metrics Agent..."
74
- curl -sSL https://repos.insights.digitalocean.com/install.sh | sudo bash
75
-
76
- sudo touch "#{marker}"
77
- echo "✅ Metrics Agent installed"
78
-
79
- ps aux | grep do-agent | grep -v grep || echo "⚠️ do-agent process not found"
80
- BASH
81
-
82
- say ssh.exec!(script)
83
- end
84
-
85
- def uninstall_agent(ssh)
86
- marker = "/usr/local/backups/setup_do_metrics.after"
87
-
88
- script = <<~BASH
89
- set -e
90
-
91
- if [ ! -f "#{marker}" ]; then
92
- echo "💡 No marker for metrics agent found. Skipping rollback."
93
- exit 0
94
- fi
95
-
96
- echo "🧹 Uninstalling DigitalOcean Metrics Agent..."
97
-
98
- if dpkg -l | grep -q do-agent; then
99
- echo "📦 Removing do-agent package..."
100
- sudo apt-get remove --purge -y do-agent
101
- else
102
- echo "💡 do-agent is not installed, skipping package removal."
103
- fi
104
-
105
- if systemctl list-unit-files | grep -q do-agent.service; then
106
- echo "✍🏻 Stopping do-agent service..."
107
- sudo systemctl stop do-agent || true
108
- sudo systemctl disable do-agent || true
109
- else
110
- echo "💡 do-agent.service not found in systemd, skipping stop/disable"
111
- fi
112
-
113
- sudo rm -f "#{marker}"
114
- echo "✅ Metrics Agent removed"
115
- BASH
116
-
117
- say ssh.exec!(script)
118
- end
119
- end
120
- end
121
- end
122
- end
123
- end
@@ -1,151 +0,0 @@
1
- require "thor"
2
- require "net/ssh"
3
- require_relative "../options_builder"
4
- require_relative "../defaults"
5
-
6
- module Kitsune
7
- module Kit
8
- module Commands
9
- class SetupDockerPrereqs < Thor
10
- namespace "setup_docker_prereqs"
11
-
12
- class_option :server_ip, aliases: "-s", required: true, desc: "Server IP address or hostname"
13
- class_option :ssh_port, aliases: "-p", desc: "SSH port"
14
- class_option :ssh_key_path, aliases: "-k", desc: "Path to your private SSH key"
15
-
16
- desc "create", "Install Docker prerequisites on the remote server"
17
- def create
18
- filled_options = Kitsune::Kit::OptionsBuilder.build(
19
- options,
20
- required: [:server_ip],
21
- defaults: Kitsune::Kit::Defaults.ssh
22
- )
23
-
24
- with_ssh_connection(filled_options) do |ssh|
25
- perform_setup(ssh)
26
- end
27
- end
28
-
29
- desc "rollback", "Remove installed Docker prerequisites from the remote server"
30
- def rollback
31
- filled_options = Kitsune::Kit::OptionsBuilder.build(
32
- options,
33
- required: [:server_ip],
34
- defaults: Kitsune::Kit::Defaults.ssh
35
- )
36
-
37
- with_ssh_connection(filled_options) do |ssh|
38
- perform_rollback(ssh)
39
- end
40
- end
41
-
42
- no_commands do
43
- def with_ssh_connection(filled_options)
44
- server = filled_options[:server_ip]
45
- port = filled_options[:ssh_port]
46
- key = File.expand_path(filled_options[:ssh_key_path])
47
-
48
- say "🔑 Connecting as deploy@#{server}:#{port}", :green
49
- Net::SSH.start(server, "deploy", port: port, keys: [key], non_interactive: true, timeout: 5) do |ssh|
50
- yield ssh
51
- end
52
- end
53
-
54
- def perform_setup(ssh)
55
- output = ssh.exec! <<~EOH
56
- set -e
57
-
58
- sudo mkdir -p /usr/local/backups
59
- sudo chown deploy:deploy /usr/local/backups
60
-
61
- BACKUP_DIR="/usr/local/backups"
62
- SCRIPT_ID="setup_docker_prereqs"
63
- BEFORE_FILE="${BACKUP_DIR}/${SCRIPT_ID}.before"
64
- AFTER_FILE="${BACKUP_DIR}/${SCRIPT_ID}.after"
65
-
66
- TARGET_PKGS=(
67
- apt-transport-https
68
- ca-certificates
69
- curl
70
- gnupg
71
- lsb-release
72
- software-properties-common
73
- )
74
-
75
- echo "✍🏻 TARGET_PKGS=(\${TARGET_PKGS[*]})"
76
-
77
- if [ ! -f "$AFTER_FILE" ]; then
78
- for pkg in "\${TARGET_PKGS[@]}"; do
79
- if dpkg -l "\$pkg" &>/dev/null; then
80
- echo "\$pkg" >> "$BEFORE_FILE"
81
- fi
82
- done
83
-
84
- echo "✍🏻 Installing prerequisites..."
85
- sudo apt-get update -y
86
- sudo apt-get install -y "\${TARGET_PKGS[@]}"
87
- sudo touch "$AFTER_FILE" && echo " - marker created at $AFTER_FILE"
88
- else
89
- echo "🔁 Already set up, ensuring latest"
90
- sudo apt-get update -y
91
- sudo apt-get install -y "\${TARGET_PKGS[@]}"
92
- echo "✅ Prerequisites are current"
93
- fi
94
- EOH
95
- say output
96
- say "✅ Docker prerequisites setup completed", :green
97
- end
98
-
99
- def perform_rollback(ssh)
100
- output = ssh.exec! <<~EOH
101
- set -e
102
-
103
- sudo mkdir -p /usr/local/backups
104
- sudo chown deploy:deploy /usr/local/backups
105
-
106
- BACKUP_DIR="/usr/local/backups"
107
- SCRIPT_ID="setup_docker_prereqs"
108
- BEFORE_FILE="${BACKUP_DIR}/${SCRIPT_ID}.before"
109
- AFTER_FILE="${BACKUP_DIR}/${SCRIPT_ID}.after"
110
-
111
- TARGET_PKGS=(
112
- apt-transport-https
113
- ca-certificates
114
- curl
115
- gnupg
116
- lsb-release
117
- software-properties-common
118
- )
119
-
120
- echo "✍🏻 TARGET_PKGS=(\${TARGET_PKGS[*]})"
121
-
122
- if [ -f "$AFTER_FILE" ]; then
123
- to_remove=()
124
- for pkg in "\${TARGET_PKGS[@]}"; do
125
- if dpkg -l "\$pkg" &>/dev/null; then
126
- if ! grep -Fxq "\$pkg" "$BEFORE_FILE"; then
127
- to_remove+=("\$pkg")
128
- fi
129
- fi
130
- done
131
-
132
- if [ \${#to_remove[@]} -gt 0 ]; then
133
- echo "🔁 Removing packages..."
134
- sudo apt-get remove -y "\${to_remove[@]}" && echo " - removed: \${to_remove[*]}"
135
- else
136
- echo " - no new packages to remove"
137
- fi
138
-
139
- sudo rm -f "$BEFORE_FILE" "$AFTER_FILE" && echo " - backups removed"
140
- else
141
- echo " - no marker for $SCRIPT_ID, skipping removal"
142
- fi
143
- EOH
144
- say output
145
- say "✅ Docker prerequisites rollback completed", :green
146
- end
147
- end
148
- end
149
- end
150
- end
151
- end
@@ -1,132 +0,0 @@
1
- require "thor"
2
- require "net/ssh"
3
- require_relative "../defaults"
4
- require_relative "../options_builder"
5
-
6
- module Kitsune
7
- module Kit
8
- module Commands
9
- class SetupFirewall < Thor
10
- namespace "setup_firewall"
11
-
12
- class_option :server_ip, aliases: "-s", required: true, desc: "Server IP address or hostname"
13
- class_option :ssh_port, aliases: "-p", desc: "SSH port"
14
- class_option :ssh_key_path, aliases: "-k", desc: "Path to your private SSH key"
15
-
16
- desc "create", "Setup UFW firewall rules on the remote server"
17
- def create
18
- filled_options = Kitsune::Kit::OptionsBuilder.build(
19
- options,
20
- required: [:server_ip],
21
- defaults: Kitsune::Kit::Defaults.ssh
22
- )
23
-
24
- with_ssh_connection(filled_options) do |ssh|
25
- perform_setup(ssh, filled_options)
26
- end
27
- end
28
-
29
- desc "rollback", "Remove UFW firewall rules and disable UFW on the remote server"
30
- def rollback
31
- filled_options = Kitsune::Kit::OptionsBuilder.build(
32
- options,
33
- required: [:server_ip],
34
- defaults: Kitsune::Kit::Defaults.ssh
35
- )
36
-
37
- with_ssh_connection(filled_options) do |ssh|
38
- perform_rollback(ssh, filled_options)
39
- end
40
- end
41
-
42
- no_commands do
43
- def with_ssh_connection(filled_options)
44
- server = filled_options[:server_ip]
45
- port = filled_options[:ssh_port]
46
- key = File.expand_path(filled_options[:ssh_key_path])
47
-
48
- say "🔑 Connecting as deploy@#{server}:#{port}", :green
49
- Net::SSH.start(server, "deploy", port: port, keys: [key], non_interactive: true, timeout: 5) do |ssh|
50
- yield ssh
51
- end
52
- end
53
-
54
- def perform_setup(ssh, filled_options)
55
- ssh_port = filled_options[:ssh_port]
56
-
57
- output = ssh.exec! <<~EOH
58
- set -e
59
-
60
- echo "✍🏻 Updating repositories and ensuring UFW is installed…"
61
- if ! dpkg -l | grep -q ufw; then
62
- sudo apt-get update -y
63
- sudo apt-get install -y ufw && echo " - ufw installed"
64
- else
65
- echo " - ufw is already installed"
66
- fi
67
-
68
- echo "✍🏻 Configuring UFW rules…"
69
- add_rule() {
70
- local rule="$1"
71
- if ! sudo ufw status | grep -q "$rule"; then
72
- sudo ufw allow "$rule" >/dev/null 2>&1 && echo " - rule '$rule' added"
73
- else
74
- echo " - rule '$rule' already exists"
75
- fi
76
- }
77
- add_rule "#{ssh_port}/tcp"
78
- add_rule "80/tcp"
79
- add_rule "443/tcp"
80
-
81
- echo "✍🏻 Enabling UFW logging…"
82
- if ! sudo ufw status verbose | grep -q "Logging: on"; then
83
- sudo ufw logging on >/dev/null 2>&1 && echo " - logging enabled"
84
- else
85
- echo " - logging was already enabled"
86
- fi
87
-
88
- echo "✍🏻 Enabling UFW…"
89
- if sudo ufw status | grep -q "Status: inactive"; then
90
- sudo ufw --force enable >/dev/null 2>&1 && echo " - UFW enabled"
91
- else
92
- echo " - UFW is already enabled"
93
- fi
94
- EOH
95
- say output
96
- say "✅ Firewall setup completed", :green
97
- end
98
-
99
- def perform_rollback(ssh, filled_options)
100
- ssh_port = filled_options[:ssh_port]
101
-
102
- output = ssh.exec! <<~EOH
103
- set -e
104
-
105
- echo "🔁 Removing UFW rules…"
106
- delete_rule() {
107
- local rule="$1"
108
- if sudo ufw status | grep -q "$rule"; then
109
- sudo ufw delete allow "$rule" >/dev/null 2>&1 && echo " - rule '$rule' removed"
110
- else
111
- echo " - rule '$rule' does not exist"
112
- fi
113
- }
114
- delete_rule "#{ssh_port}/tcp"
115
- delete_rule "80/tcp"
116
- delete_rule "443/tcp"
117
-
118
- echo "✍🏻 Disabling UFW if active…"
119
- if sudo ufw status | grep -q "Status: inactive"; then
120
- echo " - UFW is already inactive"
121
- else
122
- sudo ufw --force disable >/dev/null 2>&1 && echo " - UFW disabled"
123
- fi
124
- EOH
125
- say output
126
- say "✅ Firewall rollback completed", :green
127
- end
128
- end
129
- end
130
- end
131
- end
132
- end