vagrant-docker-certificates-manager 0.2.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.
@@ -0,0 +1,179 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "i18n"
4
+ require "yaml"
5
+
6
+ module VagrantDockerCertificatesManager
7
+ module UiHelpers
8
+ class MissingTranslationError < StandardError; end
9
+ class UnsupportedLocaleError < StandardError; end
10
+
11
+ SUPPORTED = [:en, :fr].freeze
12
+ NAMESPACE = "vdcm".freeze
13
+ OUR_SPACES = %w[messages. errors. usage. help. prompts. log. emoji. cli. add. remove. list. install.
14
+ uninstall.].freeze
15
+
16
+ EMOJI = {
17
+ success: "✅",
18
+ info: "🔍",
19
+ ongoing: "🔁",
20
+ warning: "⚠️",
21
+ error: "❌",
22
+ version: "💾",
23
+ broom: "🧹",
24
+ question: "❓"
25
+ }.freeze
26
+
27
+ module_function
28
+
29
+ def setup_i18n!
30
+ return if defined?(@i18n_setup) && @i18n_setup
31
+ ::I18n.enforce_available_locales = false
32
+ base = File.expand_path("../../locales", __dir__)
33
+ ::I18n.load_path |= Dir[File.join(base, "*.yml")]
34
+ ::I18n.available_locales = SUPPORTED
35
+ default = ((ENV["VDCM_LANG"] || ENV["LANG"] || "en")[0,2] rescue "en").to_sym
36
+ ::I18n.default_locale = SUPPORTED.include?(default) ? default : :en
37
+ ::I18n.backend.load_translations
38
+ @i18n_setup = true
39
+ end
40
+
41
+ def set_locale!(lang, strict: false)
42
+ setup_i18n!
43
+
44
+ raw = (lang || ENV["VDCM_LANG"] || ENV["LANG"] || "en").to_s
45
+ sym = raw[0, 2].to_s.downcase.to_sym
46
+ sym = :en if sym.nil? || sym == :""
47
+
48
+ unless SUPPORTED.include?(sym)
49
+ if strict
50
+ raise UnsupportedLocaleError,
51
+ "#{e(:error)} Unsupported language: #{sym}. Available: #{SUPPORTED.join(', ')}"
52
+ else
53
+ sym = :en
54
+ end
55
+ end
56
+
57
+ ::I18n.locale = sym
58
+ ::I18n.backend.load_translations
59
+ sym
60
+ end
61
+
62
+ def e(key, no_emoji: false)
63
+ return "" if no_emoji || ENV["VDCM_NO_EMOJI"] == "1"
64
+ EMOJI[key] || ""
65
+ end
66
+
67
+ def ns_key(key)
68
+ k = key.to_s
69
+ k.start_with?("#{NAMESPACE}.") ? k : "#{NAMESPACE}.#{k}"
70
+ end
71
+
72
+ def t(key, **opts)
73
+ setup_i18n!
74
+ ::I18n.t(ns_key(key), **opts)
75
+ end
76
+
77
+ def t!(key, **opts)
78
+ setup_i18n!
79
+ k = ns_key(key)
80
+ if our_key?(k) && !::I18n.exists?(k, ::I18n.locale)
81
+ raise MissingTranslationError, "#{e(:error)} [#{::I18n.locale}] Missing translation for key: #{k}"
82
+ end
83
+ ::I18n.t(k, **opts)
84
+ end
85
+
86
+ def t_hash(key)
87
+ v = t(key, default: {})
88
+ v.is_a?(Hash) ? v : {}
89
+ end
90
+
91
+ def level_to_emoji(level)
92
+ case level
93
+ when :success then :success
94
+ when :warn then :warning
95
+ when :error then :error
96
+ else :info
97
+ end
98
+ end
99
+
100
+ def say(env_or_ui, level, key = nil, raw: nil, no_emoji: false, **kv)
101
+ setup_i18n!
102
+ ui = (env_or_ui.respond_to?(:[]) ? (env_or_ui[:ui] || env_or_ui[:machine]&.ui) : env_or_ui)
103
+ msg = raw || (key ? t(key, **kv) : nil)
104
+ return if ui.nil? || msg.nil?
105
+
106
+ prefix = e(level_to_emoji(level), no_emoji: no_emoji)
107
+ line = prefix.empty? ? msg : "#{prefix} #{msg}"
108
+
109
+ case level
110
+ when :warn then ui.warn(line)
111
+ when :error then ui.error(line)
112
+ else ui.info(line)
113
+ end
114
+ end
115
+
116
+ def debug(env_or_ui, msg)
117
+ return unless ENV["VDCM_DEBUG"].to_s == "1"
118
+ say(env_or_ui, :info, nil, raw: "#{e(:question)} #{msg}")
119
+ end
120
+
121
+ def print_general_help(no_emoji: false, ui: nil)
122
+ setup_i18n!
123
+ lines = []
124
+ lines << "#{e(:info, no_emoji: no_emoji)} #{t('help.general_title')}"
125
+ lines << " #{t('cli.usage')}"
126
+ t_hash("help.commands").each_value { |line| lines << " #{line}" }
127
+
128
+ if ui
129
+ lines.each { |ln| ui.info(ln) }
130
+ else
131
+ lines.each { |ln| puts ln }
132
+ end
133
+ end
134
+
135
+ def print_topic_help(topic, no_emoji: false, ui: nil)
136
+ setup_i18n!
137
+ topic = (topic || "").to_s.strip.downcase
138
+ return print_general_help(no_emoji: no_emoji, ui: ui) if topic.empty?
139
+
140
+ base = "help.topic.#{topic}"
141
+ title = t("#{base}.title", default: nil)
142
+ usage = t("#{base}.usage", default: nil)
143
+ desc = t("#{base}.description", default: nil)
144
+ opts = t_hash("#{base}.options")
145
+ exs = ::I18n.t("#{base}.examples", default: [])
146
+
147
+ if title.nil? && usage.nil? && desc.nil? && opts.empty? && exs.empty?
148
+ return print_general_help(no_emoji: no_emoji, ui: ui)
149
+ end
150
+
151
+ lines = []
152
+ lines << "#{e(:info, no_emoji: no_emoji)} #{title || t('help.topic_fallback_title', topic: topic)}"
153
+ lines << " #{t('help.usage_label')}"
154
+ lines << " #{usage || 'vagrant certs help'}"
155
+ if desc && !desc.strip.empty?
156
+ lines << " #{t('help.description_label')}"
157
+ lines << " #{desc}"
158
+ end
159
+ unless opts.empty?
160
+ lines << " #{t('help.options_label')}"
161
+ opts.each_value { |line| lines << " #{line}" }
162
+ end
163
+ if exs.is_a?(Array) && !exs.empty?
164
+ lines << " #{t('help.examples_label')}"
165
+ exs.each { |ex| lines << " #{ex}" }
166
+ end
167
+
168
+ if ui
169
+ lines.each { |ln| ui.info(ln) }
170
+ else
171
+ lines.each { |ln| puts ln }
172
+ end
173
+ end
174
+
175
+ def our_key?(k)
176
+ OUR_SPACES.any? { |ns| k.start_with?("#{NAMESPACE}.#{ns}") || k.start_with?(ns) }
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "vagrant"
4
+ require_relative "version"
5
+ require_relative "config"
6
+ require_relative "command"
7
+ require_relative "helpers"
8
+
9
+ module VagrantDockerCertificatesManager
10
+ class Plugin < Vagrant.plugin("2")
11
+ name "docker_certificates"
12
+
13
+ UiHelpers.setup_i18n!
14
+
15
+ config(:docker_certificates) do
16
+ require_relative "config"
17
+ VagrantDockerCertificatesManager::Config
18
+ end
19
+
20
+ command("certs") { Command }
21
+
22
+ action_hook(:install_cert_on_up, :machine_action_up) do |hook|
23
+ require_relative "actions/install"
24
+ hook.after Vagrant::Action::Builtin::Provision, Actions::Install
25
+ end
26
+
27
+ action_hook(:uninstall_cert_on_destroy, :machine_action_destroy) do |hook|
28
+ require_relative "actions/uninstall"
29
+ hook.before Vagrant::Action::Builtin::GracefulHalt, Actions::Uninstall
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openssl"
4
+
5
+ module VagrantDockerCertificatesManager
6
+ module Cert
7
+ MARKER = "VDCM"
8
+
9
+ module_function
10
+
11
+ def read_cert(path)
12
+ OpenSSL::X509::Certificate.new(File.read(path))
13
+ end
14
+
15
+ def sha1(path)
16
+ cert = read_cert(path)
17
+ OpenSSL::Digest::SHA1.hexdigest(cert.to_der).upcase
18
+ end
19
+
20
+ def subject_cn(path)
21
+ cert = read_cert(path)
22
+ pair = cert.subject.to_a.find { |(k, _v, _t)| k == "CN" }
23
+ pair ? pair[1].to_s : nil
24
+ end
25
+
26
+ def default_name_from(path)
27
+ base = File.basename(path).sub(/\.(pem|crt|cer)$/i, "")
28
+ base.empty? ? "local.dev" : base
29
+ end
30
+
31
+ def nickname_for(name)
32
+ "#{MARKER}:#{name}"
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "open3"
4
+ require_relative "cert"
5
+
6
+ module VagrantDockerCertificatesManager
7
+ module OS
8
+ module_function
9
+
10
+ def detect
11
+ if defined?(Vagrant) && Vagrant.const_defined?(:Util) && Vagrant::Util.const_defined?(:Platform)
12
+ return :mac if Vagrant::Util::Platform.darwin?
13
+ return :windows if Vagrant::Util::Platform.windows?
14
+ return :linux if Vagrant::Util::Platform.linux?
15
+ else
16
+ plat = RbConfig::CONFIG["host_os"].downcase
17
+ return :mac if plat.include?("darwin")
18
+ return :windows if plat =~ /mswin|mingw|windows/
19
+ return :linux if plat.include?("linux")
20
+ end
21
+ :unknown
22
+ end
23
+
24
+ def run(cmd)
25
+ out, err, st = Open3.capture3(cmd)
26
+ [st.success?, out, err]
27
+ end
28
+
29
+ def mac_add_trusted_cert(path, name)
30
+ ok, *_ = run(%(sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "#{path}"))
31
+ ok
32
+ end
33
+
34
+ def mac_has_cert_fingerprint?(fp)
35
+ ok, out, _ = run(%(security find-certificate -a -Z /Library/Keychains/System.keychain 2>/dev/null))
36
+ return false unless ok
37
+ out.include?(fp)
38
+ end
39
+
40
+ def mac_remove_by_fp(fp)
41
+ ok, out, _ = run(%(security find-certificate -a -Z /Library/Keychains/System.keychain 2>/dev/null))
42
+ return true unless ok
43
+ hash = out.lines.find { |l| l =~ /SHA-1 hash:\s*#{fp}/i } ? fp : nil
44
+ return true unless hash
45
+ run(%(sudo security delete-certificate -Z #{hash} /Library/Keychains/System.keychain)).first
46
+ end
47
+
48
+ def linux_install_cert(path, name, nss: true, firefox: false)
49
+ dest = "/usr/local/share/ca-certificates/#{Cert::MARKER.downcase}-#{name}.crt"
50
+ ok1, = run(%(sudo cp "#{path}" "#{dest}"))
51
+ ok2, = run("sudo update-ca-certificates")
52
+ okn = true
53
+ okn &&= linux_nss_install(path, name) if nss
54
+ okf = true
55
+ okf &&= linux_firefox_install(path, name) if firefox
56
+ ok1 && ok2 && okn && okf
57
+ end
58
+
59
+ def linux_has_cert_file?(name)
60
+ File.exist?("/usr/local/share/ca-certificates/#{Cert::MARKER.downcase}-#{name}.crt")
61
+ end
62
+
63
+ def linux_uninstall_cert(name, nss: true, firefox: false)
64
+ dest = "/usr/local/share/ca-certificates/#{Cert::MARKER.downcase}-#{name}.crt"
65
+ run(%(sudo rm -f "#{dest}"))
66
+ run("sudo update-ca-certificates")
67
+ linux_nss_uninstall(name) if nss
68
+ linux_firefox_uninstall(name) if firefox
69
+ true
70
+ end
71
+
72
+ def linux_nss_install(path, name)
73
+ db = %(sql:"$HOME/.pki/nssdb")
74
+ run(%(certutil -d #{db} -A -t "C,," -n "#{Cert.nickname_for(name)}" -i "#{path}")).first
75
+ end
76
+
77
+ def linux_nss_uninstall(name)
78
+ db = %(sql:"$HOME/.pki/nssdb")
79
+ run(%(certutil -d #{db} -D -n "#{Cert.nickname_for(name)}"))
80
+ true
81
+ end
82
+
83
+ def linux_firefox_profiles
84
+ home = ENV["HOME"]
85
+ [
86
+ "#{home}/.mozilla/firefox",
87
+ "#{home}/.var/app/org.mozilla.firefox/.mozilla/firefox",
88
+ "#{home}/snap/firefox/common/.mozilla/firefox"
89
+ ].select { |d| File.directory?(d) }.flat_map { |base| Dir.glob(File.join(base, "*.default*")) }
90
+ end
91
+
92
+ def linux_firefox_install(path, name)
93
+ profiles = linux_firefox_profiles
94
+ profiles.all? do |profile|
95
+ run(%(certutil -A -n "#{Cert.nickname_for(name)}" -t "C,," -i "#{path}" -d "sql:#{profile}")).first
96
+ end
97
+ end
98
+
99
+ def linux_firefox_uninstall(name)
100
+ linux_firefox_profiles.each do |profile|
101
+ run(%(certutil -D -n "#{Cert.nickname_for(name)}" -d "sql:#{profile}"))
102
+ end
103
+ true
104
+ end
105
+
106
+ def win_install_cert(path, name)
107
+ ok, out, err = run(%(certutil -addstore -f "ROOT" "#{path}"))
108
+ return false unless ok
109
+ fp = Cert.sha1(path)
110
+ ps = %(
111
+ $cert = Get-ChildItem Cert:\\LocalMachine\\Root | Where-Object { $_.Thumbprint -eq "#{fp}" };
112
+ if ($cert) { $cert.FriendlyName = "#{Cert.nickname_for(name)}"; }
113
+ ).strip
114
+ run(%(powershell -NoProfile -NonInteractive -Command "#{ps}"))
115
+ true
116
+ end
117
+
118
+ def win_has_cert_fingerprint?(fp)
119
+ ps = %q{
120
+ $c = Get-ChildItem Cert:\LocalMachine\Root | Where-Object { $_.Thumbprint -eq "__FP__" };
121
+ if ($c) { "YES" } else { "NO" }
122
+ }.strip.gsub("__FP__", fp.to_s)
123
+
124
+ ok, out, _ = run(%(powershell -NoProfile -NonInteractive -Command "#{ps}"))
125
+ ok && out.to_s.strip == "YES"
126
+ end
127
+
128
+ def win_remove_by_fp(fp)
129
+ run(%(certutil -delstore "ROOT" #{fp})).first
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "fileutils"
5
+
6
+ module VagrantDockerCertificatesManager
7
+ module Registry
8
+ module_function
9
+
10
+ def db_path
11
+ File.join(Dir.home, ".vagrant.d", "vdcm", "certs.json")
12
+ end
13
+
14
+ def ensure_dir!
15
+ FileUtils.mkdir_p(File.dirname(db_path))
16
+ end
17
+
18
+ def load
19
+ ensure_dir!
20
+ return {} unless File.exist?(db_path)
21
+ JSON.parse(File.read(db_path))
22
+ rescue
23
+ {}
24
+ end
25
+
26
+ def save(data)
27
+ ensure_dir!
28
+ File.write(db_path, JSON.pretty_generate(data))
29
+ end
30
+
31
+ def track(fp, attrs)
32
+ data = load
33
+ data[fp] = attrs
34
+ save(data)
35
+ end
36
+
37
+ def untrack(fp)
38
+ data = load
39
+ removed = !data.delete(fp).nil?
40
+ save(data)
41
+ removed
42
+ end
43
+
44
+ def find_by_path(path)
45
+ data = load
46
+ data.find { |_fp, v| File.expand_path(v["path"]) == File.expand_path(path) }
47
+ end
48
+
49
+ def all
50
+ load
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require_relative "../helpers"
5
+
6
+ module VagrantDockerCertificatesManager
7
+ module Ui
8
+ module_function
9
+
10
+ def say(env, level, key = nil, raw: nil, **kv)
11
+ UiHelpers.say(env, level, key, raw: raw, **kv)
12
+ end
13
+
14
+ def emit(json, action, result)
15
+ if json
16
+ puts JSON.dump(result.merge(action: action))
17
+ return
18
+ end
19
+ no_emoji = ENV["VDCM_NO_EMOJI"].to_s == "1"
20
+ ok_mark = no_emoji ? "[OK]" : UiHelpers.e(:success)
21
+ ko_mark = no_emoji ? "[ERR]" : UiHelpers.e(:error)
22
+
23
+ status = result[:status] || result[:state]
24
+ if status == "success" || status == "ok"
25
+ puts "#{ok_mark} #{action}"
26
+ else
27
+ puts "#{ko_mark} #{action}: #{result[:error] || 'error'}"
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module VagrantDockerCertificatesManager
4
+ VERSION = begin
5
+ path = File.expand_path("VERSION", __dir__)
6
+ File.exist?(path) ? File.read(path).strip : "0.1.0"
7
+ rescue
8
+ "0.1.0"
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "vagrant-docker-certificates-manager/plugin"
data/locales/en.yml ADDED
@@ -0,0 +1,93 @@
1
+ en:
2
+ vdcm:
3
+ cli:
4
+ title: "Vagrant Docker Certificates Manager"
5
+ usage: "Usage: vagrant certs <add|remove|list|version|help> [options]"
6
+ opt_lang: "Force language (en|fr)"
7
+ opt_no_emoji: "Disable emoji in CLI output"
8
+ opt_help: "Show help and exit"
9
+
10
+ help:
11
+ general_title: "Vagrant Docker Certificates Manager — Commands:"
12
+ topic_header: "Help: vagrant certs %{topic}"
13
+ usage_label: "Usage:"
14
+ description_label: "Description:"
15
+ options_label: "Options:"
16
+ examples_label: "Examples:"
17
+ commands:
18
+ add: "vagrant certs add [PATH] # Install the certificate"
19
+ remove: "vagrant certs remove [PATH] # Uninstall the certificate"
20
+ list: "vagrant certs list # Show tracked certificates"
21
+ version: "vagrant certs version # Print plugin version"
22
+ help: "vagrant certs help [TOPIC] # This help"
23
+ topic:
24
+ add:
25
+ usage: "vagrant certs add <PATH_CERT_FILE> [--lang en|fr] [--no-emoji]"
26
+ description: "Install the given Root CA into the system trust store. Fails if already present."
27
+ options:
28
+ lang: "--lang <en|fr> Force language"
29
+ noemoji: "--no-emoji Disable emoji in output"
30
+ examples:
31
+ - "vagrant certs add ./certs/rootca.pem"
32
+ remove:
33
+ usage: "vagrant certs remove <PATH_CERT_FILE> [--lang en|fr] [--no-emoji]"
34
+ description: "Remove a certificate previously installed by this plugin using its path (or tracked entry)."
35
+ options:
36
+ lang: "--lang <en|fr> Force language"
37
+ noemoji: "--no-emoji Disable emoji in output"
38
+ examples:
39
+ - "vagrant certs remove ./certs/rootca.pem"
40
+ list:
41
+ usage: "vagrant certs list [--lang en|fr] [--no-emoji]"
42
+ description: "Show certificates tracked by this plugin."
43
+ options:
44
+ lang: "--lang <en|fr> Force language"
45
+ noemoji: "--no-emoji Disable emoji in output"
46
+
47
+ messages:
48
+ version_line: "v%{v}."
49
+
50
+ errors:
51
+ invalid_path: "Invalid certificate path: %{path}"
52
+ missing_path_remove: "You must provide a path for removal."
53
+ not_found_for_remove: "No tracked certificate found for path: %{path}"
54
+ already_present: "The certificate %{name} already exists."
55
+ install_failed: "Certificate installation failed."
56
+ uninstall_failed: "Certificate removal failed."
57
+ remove_failed: "Remove failed."
58
+ cert_not_found: "Certificate file not found: %{path}"
59
+ os_unsupported: "Unsupported OS for this action."
60
+ unknown_command: "Unknown command: %{cmd}"
61
+
62
+ add:
63
+ success: "Certificate %{name} installed."
64
+
65
+ remove:
66
+ success: "Certificate removed."
67
+
68
+ list:
69
+ header: "Certificates installed by this plugin:"
70
+ empty: "No certificate tracked by this plugin."
71
+
72
+ install:
73
+ start: "Installing certificate %{name} from %{path}..."
74
+ success: "Certificate %{name} installed."
75
+ fail: "Failed to install certificate %{name}."
76
+ skip: "Install on up disabled; skipping."
77
+
78
+ uninstall:
79
+ start: "Uninstalling certificate %{name}..."
80
+ success: "Certificate %{name} removed."
81
+ fail: "Failed to remove certificate %{name}."
82
+ skip: "Remove on destroy disabled; skipping."
83
+
84
+ errors:
85
+ invalid_path: "Invalid certificate path: %{path}"
86
+ missing_path_remove: "You must provide a path for removal."
87
+ not_found_for_remove: "No tracked certificate found for path: %{path}"
88
+ already_present: "The certificate %{name} already exists."
89
+ install_failed: "Certificate installation failed."
90
+ uninstall_failed: "Certificate removal failed."
91
+ remove_failed: "Remove failed."
92
+ os_unsupported: "Unsupported OS for this action."
93
+ unknown_command: "Unknown command: %{cmd}"
data/locales/fr.yml ADDED
@@ -0,0 +1,93 @@
1
+ fr:
2
+ vdcm:
3
+ cli:
4
+ title: "Gestionnaire de certificats Docker pour Vagrant"
5
+ usage: "Utilisation : vagrant certs <add|remove|list|version|help> [options]"
6
+ opt_lang: "Forcer la langue (en|fr)"
7
+ opt_no_emoji: "Désactiver les émojis dans la sortie"
8
+ opt_help: "Afficher l'aide et quitter"
9
+
10
+ help:
11
+ general_title: "Gestionnaire de certificats — Commandes :"
12
+ topic_header: "Aide : vagrant certs %{topic}"
13
+ usage_label: "Utilisation :"
14
+ description_label: "Description :"
15
+ options_label: "Options :"
16
+ examples_label: "Exemples :"
17
+ commands:
18
+ add: "vagrant certs add [CHEMIN] # Installer le certificat"
19
+ remove: "vagrant certs remove [CHEMIN] # Désinstaller le certificat"
20
+ list: "vagrant certs list # Afficher les certificats suivis"
21
+ version: "vagrant certs version # Afficher la version du plugin"
22
+ help: "vagrant certs help [SUJET] # Cette aide"
23
+ topic:
24
+ add:
25
+ usage: "vagrant certs add <CHEMIN_CERT> [--lang en|fr] [--no-emoji]"
26
+ description: "Installe la CA fournie dans le trousseau système. Échoue si elle existe déjà."
27
+ options:
28
+ lang: "--lang <en|fr> Forcer la langue"
29
+ noemoji: "--no-emoji Désactiver les émojis"
30
+ examples:
31
+ - "vagrant certs add ./certs/rootca.pem"
32
+ remove:
33
+ usage: "vagrant certs remove <CHEMIN_CERT> [--lang en|fr] [--no-emoji]"
34
+ description: "Supprime un certificat installé par ce plugin à partir de son chemin (ou de l'entrée suivie)."
35
+ options:
36
+ lang: "--lang <en|fr> Forcer la langue"
37
+ noemoji: "--no-emoji Désactiver les émojis"
38
+ examples:
39
+ - "vagrant certs remove ./certs/rootca.pem"
40
+ list:
41
+ usage: "vagrant certs list [--lang en|fr] [--no-emoji]"
42
+ description: "Affiche les certificats suivis par ce plugin."
43
+ options:
44
+ lang: "--lang <en|fr> Forcer la langue"
45
+ noemoji: "--no-emoji Désactiver les émojis"
46
+
47
+ messages:
48
+ version_line: "v%{v}."
49
+
50
+ errors:
51
+ invalid_path: "Chemin de certificat invalide : %{path}"
52
+ missing_path_remove: "Vous devez fournir un chemin pour la suppression."
53
+ not_found_for_remove: "Aucun certificat suivi pour le chemin : %{path}"
54
+ already_present: "Le certificat %{name} existe déjà."
55
+ install_failed: "Échec de l'installation du certificat."
56
+ uninstall_failed: "Échec de la suppression du certificat."
57
+ remove_failed: "Échec de la suppression."
58
+ cert_not_found: "Fichier certificat introuvable : %{path}"
59
+ os_unsupported: "Système non pris en charge pour cette action."
60
+ unknown_command: "Commande inconnue : %{cmd}"
61
+
62
+ add:
63
+ success: "Certificat %{name} installé."
64
+
65
+ remove:
66
+ success: "Certificat supprimé."
67
+
68
+ list:
69
+ header: "Certificats installés par ce plugin :"
70
+ empty: "Aucun certificat suivi par ce plugin."
71
+
72
+ install:
73
+ start: "Installation du certificat %{name} depuis %{path}…"
74
+ success: "Certificat %{name} installé."
75
+ fail: "Échec de l'installation du certificat %{name}."
76
+ skip: "Installation à l'up désactivée ; on ignore."
77
+
78
+ uninstall:
79
+ start: "Désinstallation du certificat %{name}…"
80
+ success: "Certificat %{name} supprimé."
81
+ fail: "Échec de la suppression du certificat %{name}."
82
+ skip: "Suppression à la destruction désactivée ; on ignore."
83
+
84
+ errors:
85
+ invalid_path: "Chemin de certificat invalide : %{path}"
86
+ missing_path_remove: "Vous devez fournir un chemin à supprimer."
87
+ not_found_for_remove: "Aucun certificat suivi pour le chemin : %{path}"
88
+ already_present: "Le certificat %{name} existe déjà."
89
+ install_failed: "Échec de l'installation du certificat."
90
+ uninstall_failed: "Échec de la suppression du certificat."
91
+ remove_failed: "Échec de la suppression."
92
+ os_unsupported: "Système non pris en charge pour cette action."
93
+ unknown_command: "Commande inconnue : %{cmd}"