shippy 0.2.3 → 0.2.5

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fb76c344e614e5c9a5b7d9ffe7f59bbce5890e9815d28a404b952dc19c07a8e9
4
- data.tar.gz: 4966608befe17e8cdd38a06aa69bf64457319953b6ac304b700e418439fce4cc
3
+ metadata.gz: 2c8514e699c44724105cd11bc6b9034e7fe36c992403642bba781a16e7c74aac
4
+ data.tar.gz: 5356c87f5316dff2637f5f78a0271a8fdcce4a41bfbd6fb128e3aca654087452
5
5
  SHA512:
6
- metadata.gz: c5510d52b7e52700bd74e0c0805db203c1aee5f42324f6bb92091a2dc2c72f91bf2b4bdff4b5e1fccc8be4b78c32b028fe25d6a35527159e3c8aad3509e0cadf
7
- data.tar.gz: 34686fba8c47ed0627727e55ba11fefd39db84c30fe076b177f4e25aa88ccd38cd882699e99141792b10fad0ee0b5c6323553b1de21b73451d2546384c402b9f
6
+ metadata.gz: e25771e02e107140eebaf7f8f0f90c66974040d3ebdb0258e819da8a508060d9e297d37e2e2b2e9a4d355f2f4f5491963aa7bd5440c45ca6751170d241fafc72
7
+ data.tar.gz: ea3feb9af3d644ef5e82149d09da0479cb46f010e07cdb1422dd73a58d90afac106c0db47f3b7e59b5732dc310b8876491848263c0b228fdbb4b1866d71689f2
@@ -2,10 +2,17 @@ class Shippy::Cli::App < Shippy::Cli::Base
2
2
  argument :app_name, type: :string
3
3
 
4
4
  def initialize(...)
5
- super(...)
5
+ super
6
6
  load_app
7
7
  end
8
8
 
9
+ desc "compile", "compile application"
10
+ def compile
11
+ say "compiling #{app_name} on #{SHIPPY.host}...", :magenta
12
+
13
+ SHIPPY.compile
14
+ end
15
+
9
16
  desc "deploy", "Deploy application"
10
17
  def deploy
11
18
  say "Deploying #{app_name} on #{SHIPPY.host}...", :magenta
@@ -55,4 +55,7 @@ class Shippy::Cli::Main < Shippy::Cli::Base
55
55
 
56
56
  desc "prune", "Prune old application images and containers"
57
57
  subcommand "prune", Shippy::Cli::Prune
58
+
59
+ desc "secrets", "Manage secrets"
60
+ subcommand "secrets", Shippy::Cli::Secrets
58
61
  end
@@ -0,0 +1,11 @@
1
+ class Shippy::Cli::Secrets < Shippy::Cli::Base
2
+ desc "edit", "Edit secrets"
3
+ def edit
4
+ Shippy::SecretsManager.new.edit
5
+ end
6
+
7
+ desc "view", "View secrets"
8
+ def view
9
+ puts JSON.pretty_generate(Shippy::SecretsManager.new.read)
10
+ end
11
+ end
@@ -1,6 +1,6 @@
1
1
  Shippy.define do
2
2
  service :proxy do
3
- image { "traefik:v2.9" }
3
+ image { "traefik:v3.5" }
4
4
  command { "--configFile=/config/config.yml" }
5
5
 
6
6
  environment do
File without changes
@@ -4,4 +4,4 @@ ssh:
4
4
  wildcard_domain: 'local.homelab.com'
5
5
  local_domain: local
6
6
  deploy_to: '/var/lib/homelab'
7
- secrets_file: 'config/secrets.yml'
7
+ secrets_file: 'config/secrets.yml.enc'
data/lib/shippy/cli.rb CHANGED
@@ -3,6 +3,7 @@ require_relative "cli/init"
3
3
  require_relative "cli/server"
4
4
  require_relative "cli/app"
5
5
  require_relative "cli/prune"
6
+ require_relative "cli/secrets"
6
7
  require_relative "cli/main"
7
8
 
8
9
  module Shippy::Cli
@@ -56,7 +56,7 @@ module Shippy
56
56
  def copy_template_files(file)
57
57
  new_path = build_dest(file.gsub(".erb", ""))
58
58
  mode = File.stat(file).mode
59
- template = ERB.new(File.read(file))
59
+ template = ERB.new(File.read(file), trim_mode: "-")
60
60
  result = template.result(app.get_binding)
61
61
  File.open(new_path, "wb", mode) { |f| f.write(result) }
62
62
  end
data/lib/shippy/config.rb CHANGED
@@ -4,7 +4,7 @@ module Shippy
4
4
 
5
5
  def initialize(file)
6
6
  @data = YAML.load_file(file).deep_symbolize_keys
7
- @secrets = Secrets.new(@data.fetch(:secrets_file))
7
+ @secrets = Secrets.new(@data.fetch(:secrets_file) { "config/secrets.yml.enc" })
8
8
  end
9
9
 
10
10
  def secrets(app, name)
@@ -3,7 +3,7 @@ module Shippy
3
3
  attr_reader :data
4
4
 
5
5
  def initialize(file)
6
- @data = YAML.load_file(file).deep_symbolize_keys
6
+ @data = Shippy::SecretsManager.new(content_path: file).read.deep_symbolize_keys
7
7
  end
8
8
 
9
9
  def fetch(app, name)
@@ -0,0 +1,74 @@
1
+ require "active_support"
2
+ require "active_support/encrypted_configuration"
3
+ require "tempfile"
4
+ require "fileutils"
5
+
6
+ module Shippy
7
+ class SecretsManager
8
+ attr_reader :content_path, :key_path, :output
9
+
10
+ def initialize(
11
+ content_path: "config/secrets.yml.enc",
12
+ key_path: "config/master.key",
13
+ env_key: "SHIPPY_MASTER_KEY",
14
+ output: $stdout
15
+ )
16
+ @content_path = content_path
17
+ @key_path = key_path
18
+ @env_key = env_key
19
+ @output = output
20
+
21
+ @config = ActiveSupport::EncryptedConfiguration.new(
22
+ config_path: @content_path,
23
+ key_path: @key_path,
24
+ env_key: @env_key,
25
+ raise_if_missing_key: true
26
+ )
27
+ end
28
+
29
+ def edit
30
+ ensure_key_exists!
31
+
32
+ original_content = if File.exist?(content_path)
33
+ @config.read
34
+ else
35
+ "# Add your secrets here. They will be encrypted on save.\n" \
36
+ "# keys: values\n"
37
+ end
38
+
39
+ Tempfile.create(["secrets", ".yml"]) do |tmp_file|
40
+ tmp_file.write(original_content)
41
+ tmp_file.close
42
+
43
+ editor = ENV["EDITOR"] || "vim"
44
+ system("#{editor} #{tmp_file.path}")
45
+
46
+ new_content = File.read(tmp_file.path)
47
+
48
+ if new_content != original_content
49
+ @config.write(new_content)
50
+ output.puts "✅ Secrets updated and encrypted to #{content_path}"
51
+ else
52
+ output.puts "⚠️ No changes detected."
53
+ end
54
+ end
55
+ rescue ActiveSupport::EncryptedFile::MissingKeyError
56
+ output.puts "❌ Error: Missing '#{key_path}'. Run 'setup' first to generate a key."
57
+ end
58
+
59
+ def read
60
+ YAML.safe_load(@config.read, symbolize_names: true).to_h
61
+ rescue Errno::ENOENT
62
+ {}
63
+ end
64
+
65
+ def ensure_key_exists!
66
+ return if File.exist?(key_path)
67
+
68
+ output.puts "Generating new master key at #{key_path}..."
69
+ FileUtils.mkdir_p(File.dirname(key_path))
70
+ File.write(key_path, ActiveSupport::EncryptedConfiguration.generate_key)
71
+ output.puts "⚠️ IMPORTANT: Add #{key_path} to your .gitignore!"
72
+ end
73
+ end
74
+ end
@@ -1,7 +1,7 @@
1
1
  module Shippy
2
2
  class Service
3
3
  ATTRIBUTES = %i[
4
- build command depends_on devices entrypoint environment extra_hosts hostname
4
+ build command depends_on devices entrypoint environment extra_hosts hostname
5
5
  image labels logging networks user ports restart volumes volumes_from
6
6
  working_dir security_opt
7
7
  ].freeze
@@ -56,21 +56,23 @@ module Shippy
56
56
  networks { ["lan_access"] }
57
57
  end
58
58
 
59
- def use_traefik(name:, alt: nil, port: nil, healthcheck: false)
59
+ def use_traefik(name:, alt: nil, port: nil, &block)
60
60
  labels do
61
61
  all_labels = ["traefik.enable=true"]
62
62
  all_labels += ["traefik.docker.network=lan_access"]
63
- all_labels += build_traefik_labels(name: name, port: port)
64
- all_labels += build_traefik_labels(name: alt, port: port) if alt
65
- all_labels += build_ihxator_labels(service: "https://#{name}.#{wildcard_domain}") if healthcheck
63
+ all_labels += build_traefik_labels(name: name, port: port, &block)
64
+ all_labels += build_traefik_labels(name: alt, port: port, &block) if alt
66
65
 
67
66
  all_labels
68
67
  end
69
68
  end
70
69
 
71
70
  def build_traefik_labels(name:, port: nil)
71
+ rule = "Host(`#{name}.#{wildcard_domain}`)"
72
+ rule = yield(rule) if block_given?
73
+
72
74
  [
73
- "traefik.http.routers.websecure-#{name}.rule=Host(`#{name}.#{wildcard_domain}`)",
75
+ "traefik.http.routers.websecure-#{name}.rule=#{rule}",
74
76
  "traefik.http.routers.websecure-#{name}.entrypoints=websecure",
75
77
  "traefik.http.routers.websecure-#{name}.tls=true",
76
78
  "traefik.http.routers.websecure-#{name}.tls.certresolver=ssl-resolver",
@@ -79,31 +81,16 @@ module Shippy
79
81
 
80
82
  "traefik.http.routers.web-#{name}.rule=Host(`#{name}.#{wildcard_domain}`)",
81
83
  "traefik.http.routers.web-#{name}.entrypoints=web",
82
- "traefik.http.routers.web-#{name}.middlewares=secure-redirect-scheme@file",
83
-
84
- "traefik.http.routers.#{name}-local.rule=Host(`#{name}.#{local_domain}`)",
85
- "traefik.http.routers.#{name}-local.entrypoints=web",
86
- "traefik.http.middlewares.#{name}-local.redirectregex.regex=^http://#{name}.#{local_domain}",
87
- "traefik.http.middlewares.#{name}-local.redirectregex.replacement=https://#{name}.#{wildcard_domain}",
88
- "traefik.http.middlewares.#{name}-local.redirectregex.permanent=true",
89
- "traefik.http.routers.#{name}-local.middlewares=#{name}-local@docker"
84
+ "traefik.http.routers.web-#{name}.middlewares=secure-redirect-scheme@file"
90
85
  ].tap do |labels|
91
86
  if port
92
87
  labels << "traefik.http.services.#{name}.loadbalancer.server.port=#{port}"
93
88
  labels << "traefik.http.routers.websecure-#{name}.service=#{name}"
94
89
  labels << "traefik.http.routers.web-#{name}.service=#{name}"
95
- labels << "traefik.http.routers.#{name}-local.service=#{name}"
96
90
  end
97
91
  end
98
92
  end
99
93
 
100
- def build_ihxator_labels(service:)
101
- [
102
- "ihxator.enable=true",
103
- "ihxator.service=#{service}"
104
- ]
105
- end
106
-
107
94
  def secrets(name)
108
95
  @app.secrets(name)
109
96
  end
@@ -1,3 +1,3 @@
1
1
  module Shippy
2
- VERSION = "0.2.3"
2
+ VERSION = "0.2.5"
3
3
  end
data/lib/shippy.rb CHANGED
@@ -10,6 +10,7 @@ require "zlib"
10
10
 
11
11
  require_relative "shippy/version"
12
12
  require_relative "shippy/secrets"
13
+ require_relative "shippy/secrets_manager"
13
14
  require_relative "shippy/config"
14
15
  require_relative "shippy/commander"
15
16
  require_relative "shippy/cli"
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shippy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marius Bobin
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2025-07-07 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: activesupport
@@ -148,7 +147,6 @@ dependencies:
148
147
  - - "~>"
149
148
  - !ruby/object:Gem::Version
150
149
  version: '1.3'
151
- description:
152
150
  email:
153
151
  - marius@mbobin.me
154
152
  executables:
@@ -166,11 +164,12 @@ files:
166
164
  - lib/shippy/cli/init.rb
167
165
  - lib/shippy/cli/main.rb
168
166
  - lib/shippy/cli/prune.rb
167
+ - lib/shippy/cli/secrets.rb
169
168
  - lib/shippy/cli/server.rb
170
169
  - lib/shippy/cli/templates/apps/proxy/docker-compose.rb
171
170
  - lib/shippy/cli/templates/apps/proxy/traefik/config.yml.erb
172
171
  - lib/shippy/cli/templates/apps/proxy/traefik/dynamic_config.yml
173
- - lib/shippy/cli/templates/config/secrets.yml
172
+ - lib/shippy/cli/templates/config/secrets.yml.enc
174
173
  - lib/shippy/cli/templates/config/shippy.yml
175
174
  - lib/shippy/commander.rb
176
175
  - lib/shippy/compiler.rb
@@ -178,6 +177,7 @@ files:
178
177
  - lib/shippy/config.rb
179
178
  - lib/shippy/repo.rb
180
179
  - lib/shippy/secrets.rb
180
+ - lib/shippy/secrets_manager.rb
181
181
  - lib/shippy/service.rb
182
182
  - lib/shippy/version.rb
183
183
  homepage: https://mbobin.me/shippy
@@ -187,7 +187,6 @@ metadata:
187
187
  allowed_push_host: https://rubygems.org
188
188
  homepage_uri: https://mbobin.me/shippy
189
189
  source_code_uri: https://mbobin.me/shippy
190
- post_install_message:
191
190
  rdoc_options: []
192
191
  require_paths:
193
192
  - lib
@@ -202,8 +201,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
202
201
  - !ruby/object:Gem::Version
203
202
  version: '0'
204
203
  requirements: []
205
- rubygems_version: 3.5.21
206
- signing_key:
204
+ rubygems_version: 4.0.3
207
205
  specification_version: 4
208
206
  summary: Deployment wrapper around docker-compose and SSH Kit
209
207
  test_files: []
@@ -1,3 +0,0 @@
1
- proxy:
2
- cloudflare_email: me@example.org
3
- cloudflare_token: token