Son aktivite 1 month ago

Revizyon 8b2b326c2274fdb1ac0702a640799bb0739819b1

policy.command.sh Ham
1#!/usr/bin/env bash
2# policy.command.sh — manage policies
3#
4# Subcommands:
5# wgctl policy list
6# wgctl policy show --name <name>
7# wgctl policy add --name <name> [--tunnel-mode split|full]
8# [--default-rule <rule>] [--strict-rule] [--no-auto-apply]
9# [--desc <desc>]
10# wgctl policy rm --name <name>
11# wgctl policy set --name <name> --field <field> --value <value>
12
13# ============================================
14# Lifecycle
15# ============================================
16
17function cmd::policy::on_load() {
18 load_module policy
19
20 flag::register --name
21 flag::register --tunnel-mode
22 flag::register --default-rule
23 flag::register --strict-rule
24 flag::register --no-strict-rule
25 flag::register --auto-apply
26 flag::register --no-auto-apply
27 flag::register --desc
28 flag::register --field
29 flag::register --value
30
31 command::mixin json_output
32}
33
34# ============================================
35# Help
36# ============================================
37
38function cmd::policy::help() {
39 cat <<EOF
40Usage: wgctl policy <subcommand> [options]
41
42Manage policies. Policies define behavioral flags for subnets and identities.
43
44Subcommands:
45 list List all policies
46 show --name <name> Show policy details
47 add --name <name> Add a new policy
48 [--tunnel-mode split|full]
49 [--default-rule <rule>]
50 [--strict-rule]
51 [--no-auto-apply]
52 [--desc <desc>]
53 rm --name <name> Remove a policy (built-ins cannot be removed)
54 set --name <name> Set a single field on a policy
55 --field <field>
56 --value <value>
57
58Fields:
59 tunnel_mode split|full
60 default_rule rule name (or empty to clear)
61 strict_rule true|false
62 auto_apply true|false
63 desc description string
64
65Built-in policies (cannot be removed): default, guest, trusted, server, iot
66
67Examples:
68 wgctl policy list
69 wgctl policy show --name guest
70 wgctl policy add --name contractor --default-rule contractor --strict-rule
71 wgctl policy set --name contractor --field tunnel-mode --value full
72 wgctl policy rm --name contractor
73EOF
74}
75
76# ============================================
77# Run
78# ============================================
79
80function cmd::policy::run() {
81 local subcmd="${1:-list}"
82 shift || true
83
84 if command::json; then
85 cmd::policy::_output_json
86 return 0
87 fi
88
89 case "$subcmd" in
90 list) cmd::policy::_list "$@" ;;
91 show) cmd::policy::_show "$@" ;;
92 add) cmd::policy::_add "$@" ;;
93 rm) cmd::policy::_rm "$@" ;;
94 set) cmd::policy::_set "$@" ;;
95 --help) cmd::policy::help ;;
96 *)
97 log::error "Unknown subcommand '${subcmd}'. Available: list, show, add, rm, set"
98 return 1
99 ;;
100 esac
101}
102
103# ============================================
104# Subcommands
105# ============================================
106
107function cmd::policy::_list() {
108 local data
109 data=$(policy::list_data | ui::sort_rows 1)
110
111 if [[ -z "$data" ]]; then
112 log::info "No policies defined."
113 return 0
114 fi
115
116 if display::is_table "policy_list"; then
117 cmd::policy::_render_table "$data"
118 return 0
119 fi
120
121 echo ""
122 while IFS='|' read -r name tunnel default_rule strict auto desc; do
123 ui::policy::list_row "$name" "$default_rule" "$strict" "$auto"
124 done <<< "$data"
125 echo ""
126}
127
128function cmd::policy::_render_table() {
129 local data="${1:-}"
130 [[ -z "$data" ]] && return 0
131
132 ui::policy::list_header_table
133 while IFS='|' read -r name tunnel default_rule strict auto desc; do
134 [[ -z "$name" ]] && continue
135 ui::policy::list_row_table "$name" "$tunnel" "$default_rule" "$strict" "$auto"
136 done <<< "$data"
137 printf "\n"
138}
139
140
141function cmd::policy::_show() {
142 local name=""
143 while [[ $# -gt 0 ]]; do
144 case "$1" in
145 --name) name="$2"; shift 2 ;;
146 --help) cmd::policy::help; return ;;
147 *) log::error "Unknown flag: $1"; return 1 ;;
148 esac
149 done
150
151 [[ -z "$name" ]] && { log::error "Missing required flag: --name"; return 1; }
152 policy::require_exists "$name" || return 1
153
154 local dr tunnel strict auto
155 dr=$(policy::default_rule "$name")
156 tunnel=$(policy::tunnel_mode "$name")
157 strict=$(policy::strict_rule "$name" && echo "yes" || echo "no")
158 auto=$(policy::auto_apply "$name" && echo "yes" || echo "no")
159
160 local rule_val="-"
161 [[ -n "$dr" ]] && rule_val="$dr"
162
163 local strict_padded
164 strict_padded=$(printf "%-4s" "$strict")
165
166 # First line — mirrors list format
167 echo ""
168 printf " \033[1m%-14s\033[0m \033[2mrule:\033[0m %-16s \033[2mstrict:\033[0m %s\n" \
169 "$name" "$rule_val" "$strict_padded"
170 echo ""
171
172 # Detail section
173 local desc
174 desc=$(policy::get "$name" "desc")
175 [[ -n "$desc" ]] && printf " \033[2mDescription:\033[0m %s\n" "$desc"
176 printf " \033[2mTunnel:\033[0m %s\n" "$tunnel"
177 printf " \033[2mAuto apply:\033[0m %s\n" "$auto"
178 echo ""
179}
180
181function cmd::policy::_add() {
182 local name="" tunnel_mode="split" default_rule="" \
183 strict_rule="false" auto_apply="true" desc=""
184
185 while [[ $# -gt 0 ]]; do
186 case "$1" in
187 --name) name="$2"; shift 2 ;;
188 --tunnel-mode) tunnel_mode="$2"; shift 2 ;;
189 --default-rule) default_rule="$2"; shift 2 ;;
190 --strict-rule) strict_rule="true"; shift ;;
191 --no-strict-rule) strict_rule="false"; shift ;;
192 --no-auto-apply) auto_apply="false"; shift ;;
193 --auto-apply) auto_apply="true"; shift ;;
194 --desc) desc="$2"; shift 2 ;;
195 --help) cmd::policy::help; return ;;
196 *) log::error "Unknown flag: $1"; return 1 ;;
197 esac
198 done
199
200 [[ -z "$name" ]] && { log::error "Missing required flag: --name"; return 1; }
201
202 case "$tunnel_mode" in
203 split|full) ;;
204 *) log::error "Invalid --tunnel-mode '${tunnel_mode}'. Use: split, full"; return 1 ;;
205 esac
206
207 json::policy_add "$(ctx::policies)" "$name" "$tunnel_mode" \
208 "$default_rule" "$strict_rule" "$auto_apply" "$desc"
209 log::ok "Policy '${name}' added"
210}
211
212function cmd::policy::_rm() {
213 local name=""
214 while [[ $# -gt 0 ]]; do
215 case "$1" in
216 --name) name="$2"; shift 2 ;;
217 --help) cmd::policy::help; return ;;
218 *) log::error "Unknown flag: $1"; return 1 ;;
219 esac
220 done
221
222 [[ -z "$name" ]] && { log::error "Missing required flag: --name"; return 1; }
223 policy::require_exists "$name" || return 1
224
225 json::policy_remove "$(ctx::policies)" "$name"
226 log::ok "Policy '${name}' removed"
227}
228
229function cmd::policy::_set() {
230 local name="" field="" value=""
231 while [[ $# -gt 0 ]]; do
232 case "$1" in
233 --name) name="$2"; shift 2 ;;
234 --field) field="$2"; shift 2 ;;
235 --value) value="$2"; shift 2 ;;
236 --help) cmd::policy::help; return ;;
237 *) log::error "Unknown flag: $1"; return 1 ;;
238 esac
239 done
240
241 [[ -z "$name" ]] && { log::error "Missing required flag: --name"; return 1; }
242 [[ -z "$field" ]] && { log::error "Missing required flag: --field"; return 1; }
243 [[ -z "$value" ]] && { log::error "Missing required flag: --value"; return 1; }
244
245 policy::require_exists "$name" || return 1
246
247 # Normalise field name (allow tunnel-mode as well as tunnel_mode)
248 field="${field//-/_}"
249
250 case "$field" in
251 tunnel_mode)
252 case "$value" in
253 split|full) ;;
254 *) log::error "Invalid value '${value}' for tunnel_mode. Use: split, full"; return 1 ;;
255 esac
256 ;;
257 strict_rule|auto_apply)
258 case "$value" in
259 true|false) ;;
260 *) log::error "Invalid value '${value}' for ${field}. Use: true, false"; return 1 ;;
261 esac
262 ;;
263 default_rule|desc) ;;
264 *)
265 log::error "Unknown field '${field}'. Valid: tunnel_mode, default_rule, strict_rule, auto_apply, desc"
266 return 1
267 ;;
268 esac
269
270 json::policy_set_field "$(ctx::policies)" "$name" "$field" "$value"
271 log::ok "Policy '${name}': ${field} = ${value}"
272}
273
274function cmd::policy::_output_json() {
275 local data
276 data=$(policy::list_data 2>/dev/null)
277
278 local -a policies=()
279 while IFS='|' read -r name tunnel_mode default_rule strict_rule auto_apply desc; do
280 [[ -z "$name" ]] && continue
281
282 local strict_json="false"
283 [[ "$strict_rule" == "true" ]] && strict_json="true"
284 local auto_json="true"
285 [[ "$auto_apply" == "false" ]] && auto_json="false"
286
287 policies+=("$(printf '{"name":"%s","tunnel_mode":"%s","default_rule":"%s","strict_rule":%s,"auto_apply":%s,"desc":"%s"}' \
288 "$name" "$tunnel_mode" "${default_rule:-}" \
289 "$strict_json" "$auto_json" "$desc")")
290 done <<< "$data"
291
292 local count=${#policies[@]}
293 local array
294 array=$(printf '%s\n' "${policies[@]:-}" | paste -sd ',' -)
295 printf '{"policies":[%s]}' "${array:-}" | json::envelope "policy list" "$count"
296}