• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

knowledgepixels / nanopub-registry / 24121799241

08 Apr 2026 06:42AM UTC coverage: 32.765% (-0.6%) from 33.374%
24121799241

push

github

tkuhn
Merge branch 'feat/agent-quota-enforcement'

263 of 888 branches covered (29.62%)

Branch coverage included in aggregate %.

793 of 2335 relevant lines covered (33.96%)

5.68 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

51.09
src/main/java/com/knowledgepixels/registry/AgentFilter.java
1
package com.knowledgepixels.registry;
2

3
import com.mongodb.client.ClientSession;
4
import org.bson.Document;
5
import org.slf4j.Logger;
6
import org.slf4j.LoggerFactory;
7

8
import java.util.Collections;
9
import java.util.HashMap;
10
import java.util.Map;
11

12
import static com.knowledgepixels.registry.RegistryDB.collection;
13

14
/**
15
 * Controls which pubkeys are allowed to publish nanopubs and what their quotas are.
16
 * Configured via REGISTRY_COVERAGE_AGENTS env var.
17
 *
18
 * Format: whitespace-separated entries, each being either:
19
 * - "viaSetting" — include all agents approved by the trust network (with computed quotas)
20
 * - "pubkeyHash:quota" — include a specific pubkey with an explicit quota
21
 *
22
 * Example: viaSetting abc123...def456:5000 789xyz...abc012:10000
23
 *
24
 * When unset, defaults to viaSetting (all trusted agents, no restrictions).
25
 */
26
public final class AgentFilter {
27

28
    private static final Logger logger = LoggerFactory.getLogger(AgentFilter.class);
9✔
29

30
    private static volatile boolean viaSetting = true;
6✔
31
    private static volatile Map<String, Integer> explicitPubkeys = Collections.emptyMap();
9✔
32

33
    private AgentFilter() {}
34

35
    /**
36
     * Initializes the agent filter from the REGISTRY_COVERAGE_AGENTS env var.
37
     */
38
    public static void init() {
39
        String config = Utils.getEnv("REGISTRY_COVERAGE_AGENTS", "viaSetting");
12✔
40
        boolean via = false;
6✔
41
        Map<String, Integer> pubkeys = new HashMap<>();
12✔
42

43
        for (String entry : config.trim().split("\\s+")) {
57✔
44
            if (entry.isEmpty()) continue;
9!
45
            if ("viaSetting".equals(entry)) {
12✔
46
                via = true;
9✔
47
            } else if (entry.contains(":")) {
12✔
48
                String[] parts = entry.split(":", 2);
15✔
49
                String pubkeyHash = parts[0];
12✔
50
                int quota;
51
                try {
52
                    quota = Integer.parseInt(parts[1]);
15✔
53
                } catch (NumberFormatException e) {
3✔
54
                    throw new IllegalArgumentException(
18✔
55
                            "Invalid quota in REGISTRY_COVERAGE_AGENTS: " + entry);
56
                }
3✔
57
                pubkeys.put(pubkeyHash, quota);
18✔
58
            } else {
3✔
59
                throw new IllegalArgumentException(
18✔
60
                        "Invalid entry in REGISTRY_COVERAGE_AGENTS: " + entry
61
                                + " (expected 'viaSetting' or 'pubkeyHash:quota')");
62
            }
63
        }
64

65
        viaSetting = via;
6✔
66
        explicitPubkeys = Collections.unmodifiableMap(pubkeys);
9✔
67

68
        if (via && pubkeys.isEmpty()) {
15✔
69
            logger.info("Agent filter: viaSetting (all trusted agents)");
12✔
70
        } else if (via) {
6✔
71
            logger.info("Agent filter: viaSetting + {} explicit pubkeys", pubkeys.size());
21✔
72
        } else {
73
            logger.info("Agent filter: {} explicit pubkeys only", pubkeys.size());
18✔
74
        }
75

76
        if (via && "false".equals(System.getenv("REGISTRY_ENABLE_TRUST_CALCULATION"))) {
21!
77
            logger.warn("viaSetting is enabled but trust calculation is disabled — " +
×
78
                    "no agents will be discovered via the trust network; only explicit pubkeys will work");
79
        }
80
    }
3✔
81

82
    /**
83
     * Returns true if the trust network (viaSetting) is used for agent approval.
84
     */
85
    public static boolean usesViaSetting() {
86
        return viaSetting;
6✔
87
    }
88

89
    /**
90
     * Returns the explicitly configured pubkeys with their quotas.
91
     */
92
    public static Map<String, Integer> getExplicitPubkeys() {
93
        return explicitPubkeys;
6✔
94
    }
95

96
    /**
97
     * Returns the quota for a given pubkey, checking explicit config first,
98
     * then the accounts collection for trust-computed quotas.
99
     * Returns -1 if the pubkey is not allowed.
100
     */
101
    public static int getQuota(ClientSession session, String pubkeyHash) {
102
        // Explicit pubkeys take precedence
103
        if (explicitPubkeys.containsKey(pubkeyHash)) {
×
104
            return explicitPubkeys.get(pubkeyHash);
×
105
        }
106

107
        // Check trust network if enabled
108
        if (viaSetting) {
×
109
            Document account = collection(Collection.ACCOUNTS.toString()).find(session,
×
110
                    new Document("pubkey", pubkeyHash).append("status", "loaded")).first();
×
111
            if (account != null && account.get("quota") != null) {
×
112
                return account.getInteger("quota");
×
113
            }
114
            // Also accept toLoad accounts (approved but not yet fully loaded)
115
            account = collection(Collection.ACCOUNTS.toString()).find(session,
×
116
                    new Document("pubkey", pubkeyHash).append("status", "toLoad")).first();
×
117
            if (account != null && account.get("quota") != null) {
×
118
                return account.getInteger("quota");
×
119
            }
120
        }
121

122
        return -1; // not allowed
×
123
    }
124

125
    /**
126
     * Returns true if the given pubkey is allowed to publish (has a quota >= 0).
127
     */
128
    public static boolean isAllowed(ClientSession session, String pubkeyHash) {
129
        return getQuota(session, pubkeyHash) >= 0;
×
130
    }
131

132
    /**
133
     * Returns true if the given pubkey has exceeded its quota.
134
     * Checks the current nanopub count for this pubkey against its quota.
135
     */
136
    public static boolean isOverQuota(ClientSession session, String pubkeyHash) {
137
        int quota = getQuota(session, pubkeyHash);
×
138
        if (quota < 0) return true; // not allowed at all
×
139

140
        // Count nanopubs for this pubkey via the "$" list position
141
        Document listDoc = collection("lists").find(session,
×
142
                new Document("pubkey", pubkeyHash).append("type", "$")).first();
×
143
        long currentCount = (listDoc != null && listDoc.get("maxPosition") != null)
×
144
                ? listDoc.getLong("maxPosition") + 1 : 0;
×
145

146
        return currentCount >= quota;
×
147
    }
148
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc