Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.92% covered (success)
97.92%
47 / 48
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
SignatureFlowPolicy
97.92% covered (success)
97.92%
47 / 48
50.00% covered (danger)
50.00%
1 / 2
13
0.00% covered (danger)
0.00%
0 / 1
 keys
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 get
97.78% covered (success)
97.78%
44 / 45
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3declare(strict_types=1);
4/**
5 * SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
6 * SPDX-License-Identifier: AGPL-3.0-or-later
7 */
8
9namespace OCA\Libresign\Service\Policy\Provider\Signature;
10
11use OCA\Libresign\Enum\SignatureFlow;
12use OCA\Libresign\Service\Policy\Contract\IPolicyDefinition;
13use OCA\Libresign\Service\Policy\Contract\IPolicyDefinitionProvider;
14use OCA\Libresign\Service\Policy\Model\PolicyContext;
15use OCA\Libresign\Service\Policy\Model\PolicyLayer;
16use OCA\Libresign\Service\Policy\Model\PolicySpec;
17use OCA\Libresign\Service\Policy\Provider\Helper\DelegationLayerHelper;
18use OCA\Libresign\Service\Policy\Provider\Helper\PolicyKeyNormalizer;
19
20final class SignatureFlowPolicy implements IPolicyDefinitionProvider {
21    public const KEY = 'signature_flow';
22    public const SYSTEM_APP_CONFIG_KEY = 'policy.signature_flow.system';
23
24    #[\Override]
25    public function keys(): array {
26        return [
27            self::KEY,
28        ];
29    }
30
31    #[\Override]
32    public function get(string|\BackedEnum $policyKey): IPolicyDefinition {
33        return match (PolicyKeyNormalizer::normalize($policyKey)) {
34            self::KEY => new PolicySpec(
35                key: self::KEY,
36                defaultSystemValue: SignatureFlow::NONE->value,
37                allowedValues: [
38                    SignatureFlow::NONE->value,
39                    SignatureFlow::PARALLEL->value,
40                    SignatureFlow::ORDERED_NUMERIC->value,
41                ],
42                normalizer: static function (mixed $rawValue): mixed {
43                    if ($rawValue instanceof SignatureFlow) {
44                        return $rawValue->value;
45                    }
46
47                    return $rawValue;
48                },
49                appConfigKey: self::SYSTEM_APP_CONFIG_KEY,
50                supportsRequestOverride: true,
51                requestLifecycle: PolicySpec::LIFECYCLE_REQUEST_SNAPSHOT,
52                groupPolicyManager: static function (PolicyContext $context, ?PolicyLayer $systemPolicy, array $groupLayers): bool {
53                    $actorRole = $context->getActorRole();
54                    if ($actorRole->canManageSystemPolicies) {
55                        return true;
56                    }
57
58                    if (!$actorRole->canManageGroupPolicies) {
59                        return false;
60                    }
61
62                    if ($actorRole->manageableGroupCount < 1) {
63                        return false;
64                    }
65
66                    return DelegationLayerHelper::hasExplicitGlobalDelegation($systemPolicy)
67                        || DelegationLayerHelper::hasSystemCreatedGroupDelegation($groupLayers);
68                },
69                systemCreatedGroupRuleEditor: static function (PolicyContext $context, ?PolicyLayer $systemPolicy, PolicyLayer $existingPolicy): bool {
70                    $actorRole = $context->getActorRole();
71                    if ($actorRole->canManageSystemPolicies) {
72                        return true;
73                    }
74
75                    if (!$actorRole->canManageGroupPolicies) {
76                        return false;
77                    }
78
79                    if (!$existingPolicy->isVisibleToChild() || !$existingPolicy->isAllowChildOverride() || $existingPolicy->getValue() === null) {
80                        return false;
81                    }
82
83                    if (DelegationLayerHelper::hasExplicitGlobalDelegation($systemPolicy)) {
84                        return true;
85                    }
86
87                    return $existingPolicy->isCreatedBySystemAdmin();
88                },
89                supportsGroupAdminDelegation: true,
90                resolutionMode: PolicySpec::RESOLUTION_MODE_VALUE_CHOICE,
91            ),
92            default => throw new \InvalidArgumentException('Unknown policy key: ' . PolicyKeyNormalizer::normalize($policyKey)),
93        };
94    }
95
96}