@mmmbuto/masix 0.4.0 → 0.4.2

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.
Files changed (42) hide show
  1. package/README.md +18 -14
  2. package/install.js +53 -27
  3. package/package.json +4 -3
  4. package/packages/plugin-base/codex-backend/0.1.4/SHA256SUMS +3 -0
  5. package/packages/plugin-base/codex-backend/0.1.4/codex-backend-android-aarch64-termux.pkg +0 -0
  6. package/packages/plugin-base/codex-backend/0.1.4/codex-backend-linux-x86_64.pkg +0 -0
  7. package/packages/plugin-base/codex-backend/0.1.4/codex-backend-macos-aarch64.pkg +0 -0
  8. package/packages/plugin-base/codex-backend/0.1.4/manifest.json +33 -0
  9. package/packages/plugin-base/codex-backend/CHANGELOG.md +17 -0
  10. package/packages/plugin-base/codex-backend/README.md +33 -0
  11. package/packages/plugin-base/codex-backend/source/Cargo.toml +25 -0
  12. package/packages/plugin-base/codex-backend/source/README-PACKAGE.txt +54 -0
  13. package/packages/plugin-base/codex-backend/source/plugin.manifest.json +103 -0
  14. package/packages/plugin-base/codex-backend/source/src/error.rs +60 -0
  15. package/packages/plugin-base/codex-backend/source/src/exec.rs +436 -0
  16. package/packages/plugin-base/codex-backend/source/src/http_backend.rs +1198 -0
  17. package/packages/plugin-base/codex-backend/source/src/lib.rs +328 -0
  18. package/packages/plugin-base/codex-backend/source/src/patch.rs +767 -0
  19. package/packages/plugin-base/codex-backend/source/src/policy.rs +297 -0
  20. package/packages/plugin-base/codex-backend/source/src/tools.rs +72 -0
  21. package/packages/plugin-base/codex-backend/source/src/workspace.rs +433 -0
  22. package/packages/plugin-base/codex-tools/0.1.3/SHA256SUMS +3 -0
  23. package/packages/plugin-base/codex-tools/0.1.3/codex-tools-android-aarch64-termux.pkg +0 -0
  24. package/packages/plugin-base/codex-tools/0.1.3/codex-tools-linux-x86_64.pkg +0 -0
  25. package/packages/plugin-base/codex-tools/0.1.3/codex-tools-macos-aarch64.pkg +0 -0
  26. package/packages/plugin-base/codex-tools/0.1.3/manifest.json +33 -0
  27. package/packages/plugin-base/codex-tools/CHANGELOG.md +17 -0
  28. package/packages/plugin-base/codex-tools/README.md +33 -0
  29. package/packages/plugin-base/codex-tools/source/Cargo.toml +23 -0
  30. package/packages/plugin-base/codex-tools/source/plugin.manifest.json +124 -0
  31. package/packages/plugin-base/codex-tools/source/src/main.rs +995 -0
  32. package/packages/plugin-base/discovery/0.2.4/SHA256SUMS +3 -0
  33. package/packages/plugin-base/discovery/0.2.4/discovery-android-aarch64-termux.pkg +0 -0
  34. package/packages/plugin-base/discovery/0.2.4/discovery-linux-x86_64.pkg +0 -0
  35. package/packages/plugin-base/discovery/0.2.4/discovery-macos-aarch64.pkg +0 -0
  36. package/packages/plugin-base/discovery/0.2.4/manifest.json +31 -0
  37. package/packages/plugin-base/discovery/CHANGELOG.md +17 -0
  38. package/packages/plugin-base/discovery/README.md +48 -0
  39. package/packages/plugin-base/discovery/source/Cargo.toml +14 -0
  40. package/packages/plugin-base/discovery/source/plugin.manifest.json +30 -0
  41. package/packages/plugin-base/discovery/source/src/main.rs +2570 -0
  42. package/prebuilt/masix +0 -0
@@ -0,0 +1,297 @@
1
+ //! Admin policy enforcement for codex-backend module
2
+ //!
3
+ //! This module enforces admin-only execution for the coding backend.
4
+ //! The policy is designed to integrate with MasiX's role-based permission system.
5
+
6
+ use crate::CodingError;
7
+
8
+ /// Permission levels matching MasiX core
9
+ #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
10
+ pub enum PermissionLevel {
11
+ #[default]
12
+ Readonly,
13
+ User,
14
+ Admin,
15
+ }
16
+
17
+ impl PermissionLevel {
18
+ pub fn as_str(&self) -> &'static str {
19
+ match self {
20
+ PermissionLevel::Readonly => "readonly",
21
+ PermissionLevel::User => "user",
22
+ PermissionLevel::Admin => "admin",
23
+ }
24
+ }
25
+
26
+ pub fn from_str(s: &str) -> Option<Self> {
27
+ match s.to_lowercase().as_str() {
28
+ "readonly" | "read-only" | "read_only" => Some(PermissionLevel::Readonly),
29
+ "user" => Some(PermissionLevel::User),
30
+ "admin" | "administrator" => Some(PermissionLevel::Admin),
31
+ _ => None,
32
+ }
33
+ }
34
+
35
+ /// Returns true if this level has admin privileges
36
+ pub fn is_admin(&self) -> bool {
37
+ matches!(self, PermissionLevel::Admin)
38
+ }
39
+ }
40
+
41
+ /// Policy context provided by the runtime
42
+ #[derive(Debug, Clone, Default)]
43
+ pub struct PolicyContext {
44
+ /// User's permission level
45
+ pub permission_level: PermissionLevel,
46
+ /// User ID (for logging)
47
+ pub user_id: Option<String>,
48
+ /// Chat ID (for logging)
49
+ pub chat_id: Option<i64>,
50
+ /// Account tag (for multi-bot isolation)
51
+ pub account_tag: Option<String>,
52
+ /// Whether policy enforcement is enabled
53
+ pub enforcement_enabled: bool,
54
+ }
55
+
56
+ impl PolicyContext {
57
+ /// Create a new policy context with the given permission level
58
+ pub fn new(level: PermissionLevel) -> Self {
59
+ Self {
60
+ permission_level: level,
61
+ enforcement_enabled: true,
62
+ ..Default::default()
63
+ }
64
+ }
65
+
66
+ /// Create an admin context (for testing or privileged execution)
67
+ pub fn admin() -> Self {
68
+ Self {
69
+ permission_level: PermissionLevel::Admin,
70
+ enforcement_enabled: true,
71
+ ..Default::default()
72
+ }
73
+ }
74
+
75
+ /// Create a readonly context
76
+ pub fn readonly() -> Self {
77
+ Self {
78
+ permission_level: PermissionLevel::Readonly,
79
+ enforcement_enabled: true,
80
+ ..Default::default()
81
+ }
82
+ }
83
+
84
+ /// Create a user context
85
+ pub fn user() -> Self {
86
+ Self {
87
+ permission_level: PermissionLevel::User,
88
+ enforcement_enabled: true,
89
+ ..Default::default()
90
+ }
91
+ }
92
+
93
+ /// Disable policy enforcement (for local/CLI use)
94
+ pub fn unenforced() -> Self {
95
+ Self {
96
+ enforcement_enabled: false,
97
+ ..Default::default()
98
+ }
99
+ }
100
+
101
+ /// Set user ID
102
+ pub fn with_user_id(mut self, user_id: impl Into<String>) -> Self {
103
+ self.user_id = Some(user_id.into());
104
+ self
105
+ }
106
+
107
+ /// Set chat ID
108
+ pub fn with_chat_id(mut self, chat_id: i64) -> Self {
109
+ self.chat_id = Some(chat_id);
110
+ self
111
+ }
112
+
113
+ /// Set account tag
114
+ pub fn with_account_tag(mut self, tag: impl Into<String>) -> Self {
115
+ self.account_tag = Some(tag.into());
116
+ self
117
+ }
118
+ }
119
+
120
+ /// Admin policy checker for codex-backend
121
+ #[derive(Debug, Clone, Default)]
122
+ pub struct AdminPolicy {
123
+ /// Whether admin is required (default: true)
124
+ require_admin: bool,
125
+ /// Whether enforcement is enabled
126
+ enforcement_enabled: bool,
127
+ }
128
+
129
+ impl AdminPolicy {
130
+ /// Create a new admin policy with enforcement enabled
131
+ pub fn new() -> Self {
132
+ Self {
133
+ require_admin: true,
134
+ enforcement_enabled: true,
135
+ }
136
+ }
137
+
138
+ /// Create a policy that doesn't require admin (for testing)
139
+ pub fn permissive() -> Self {
140
+ Self {
141
+ require_admin: false,
142
+ enforcement_enabled: true,
143
+ }
144
+ }
145
+
146
+ /// Create a policy with enforcement disabled (for CLI/local use)
147
+ pub fn disabled() -> Self {
148
+ Self {
149
+ require_admin: true,
150
+ enforcement_enabled: false,
151
+ }
152
+ }
153
+
154
+ /// Check if a task is allowed based on policy context
155
+ pub fn check(&self, context: Option<&PolicyContext>) -> Result<(), CodingError> {
156
+ // If enforcement is disabled, always allow
157
+ if !self.enforcement_enabled {
158
+ return Ok(());
159
+ }
160
+
161
+ // If admin is not required, always allow
162
+ if !self.require_admin {
163
+ return Ok(());
164
+ }
165
+
166
+ // If no context provided, deny (fail-safe)
167
+ let ctx = context.ok_or_else(|| {
168
+ CodingError::PolicyError("Policy context required but not provided".into())
169
+ })?;
170
+
171
+ // If context has enforcement disabled, allow
172
+ if !ctx.enforcement_enabled {
173
+ return Ok(());
174
+ }
175
+
176
+ // Check permission level
177
+ if ctx.permission_level.is_admin() {
178
+ return Ok(());
179
+ }
180
+
181
+ // Deny with detailed error
182
+ Err(CodingError::PolicyError(format!(
183
+ "Admin privileges required. User '{}' has level '{}'",
184
+ ctx.user_id.as_deref().unwrap_or("unknown"),
185
+ ctx.permission_level.as_str()
186
+ )))
187
+ }
188
+
189
+ /// Returns true if admin is required
190
+ pub fn requires_admin(&self) -> bool {
191
+ self.require_admin && self.enforcement_enabled
192
+ }
193
+ }
194
+
195
+ #[cfg(test)]
196
+ mod tests {
197
+ use super::*;
198
+
199
+ #[test]
200
+ fn test_permission_level_is_admin() {
201
+ assert!(PermissionLevel::Admin.is_admin());
202
+ assert!(!PermissionLevel::User.is_admin());
203
+ assert!(!PermissionLevel::Readonly.is_admin());
204
+ }
205
+
206
+ #[test]
207
+ fn test_permission_level_from_str() {
208
+ assert_eq!(
209
+ PermissionLevel::from_str("admin"),
210
+ Some(PermissionLevel::Admin)
211
+ );
212
+ assert_eq!(
213
+ PermissionLevel::from_str("user"),
214
+ Some(PermissionLevel::User)
215
+ );
216
+ assert_eq!(
217
+ PermissionLevel::from_str("readonly"),
218
+ Some(PermissionLevel::Readonly)
219
+ );
220
+ assert_eq!(PermissionLevel::from_str("invalid"), None);
221
+ }
222
+
223
+ #[test]
224
+ fn test_policy_context_admin() {
225
+ let ctx = PolicyContext::admin();
226
+ assert!(ctx.permission_level.is_admin());
227
+ assert!(ctx.enforcement_enabled);
228
+ }
229
+
230
+ #[test]
231
+ fn test_admin_policy_check_admin() {
232
+ let policy = AdminPolicy::new();
233
+ let ctx = PolicyContext::admin();
234
+ assert!(policy.check(Some(&ctx)).is_ok());
235
+ }
236
+
237
+ #[test]
238
+ fn test_admin_policy_check_user_denied() {
239
+ let policy = AdminPolicy::new();
240
+ let ctx = PolicyContext::user();
241
+ assert!(policy.check(Some(&ctx)).is_err());
242
+ }
243
+
244
+ #[test]
245
+ fn test_admin_policy_check_readonly_denied() {
246
+ let policy = AdminPolicy::new();
247
+ let ctx = PolicyContext::readonly();
248
+ let result = policy.check(Some(&ctx));
249
+ assert!(result.is_err());
250
+ if let Err(CodingError::PolicyError(msg)) = result {
251
+ assert!(msg.contains("Admin privileges required"));
252
+ } else {
253
+ panic!("Expected PolicyError");
254
+ }
255
+ }
256
+
257
+ #[test]
258
+ fn test_admin_policy_check_no_context_denied() {
259
+ let policy = AdminPolicy::new();
260
+ let result = policy.check(None);
261
+ assert!(result.is_err());
262
+ }
263
+
264
+ #[test]
265
+ fn test_admin_policy_permissive() {
266
+ let policy = AdminPolicy::permissive();
267
+ let ctx = PolicyContext::readonly();
268
+ assert!(policy.check(Some(&ctx)).is_ok());
269
+ }
270
+
271
+ #[test]
272
+ fn test_admin_policy_disabled() {
273
+ let policy = AdminPolicy::disabled();
274
+ assert!(policy.check(None).is_ok());
275
+ }
276
+
277
+ #[test]
278
+ fn test_policy_context_unenforced() {
279
+ let ctx = PolicyContext::unenforced();
280
+ assert!(!ctx.enforcement_enabled);
281
+
282
+ let policy = AdminPolicy::new();
283
+ assert!(policy.check(Some(&ctx)).is_ok());
284
+ }
285
+
286
+ #[test]
287
+ fn test_policy_context_builder() {
288
+ let ctx = PolicyContext::admin()
289
+ .with_user_id("test_user")
290
+ .with_chat_id(12345)
291
+ .with_account_tag("test_account");
292
+
293
+ assert_eq!(ctx.user_id, Some("test_user".to_string()));
294
+ assert_eq!(ctx.chat_id, Some(12345));
295
+ assert_eq!(ctx.account_tag, Some("test_account".to_string()));
296
+ }
297
+ }
@@ -0,0 +1,72 @@
1
+ use serde_json::json;
2
+
3
+ pub fn get_read_tools() -> Vec<serde_json::Value> {
4
+ vec![
5
+ json!({
6
+ "type": "function",
7
+ "function": {
8
+ "name": "read_file",
9
+ "description": "Read the contents of a file",
10
+ "parameters": {
11
+ "type": "object",
12
+ "properties": {
13
+ "path": {"type": "string", "description": "File path relative to repo root"}
14
+ },
15
+ "required": ["path"]
16
+ }
17
+ }
18
+ }),
19
+ json!({
20
+ "type": "function",
21
+ "function": {
22
+ "name": "list_dir",
23
+ "description": "List contents of a directory",
24
+ "parameters": {
25
+ "type": "object",
26
+ "properties": {
27
+ "path": {"type": "string", "description": "Directory path relative to repo root"}
28
+ },
29
+ "required": ["path"]
30
+ }
31
+ }
32
+ }),
33
+ ]
34
+ }
35
+
36
+ pub fn get_write_tools() -> Vec<serde_json::Value> {
37
+ let mut tools = get_read_tools();
38
+ tools.push(json!({
39
+ "type": "function",
40
+ "function": {
41
+ "name": "write_file",
42
+ "description": "Write content to a file (creates or overwrites)",
43
+ "parameters": {
44
+ "type": "object",
45
+ "properties": {
46
+ "path": {"type": "string", "description": "File path relative to repo root"},
47
+ "content": {"type": "string", "description": "Content to write"}
48
+ },
49
+ "required": ["path", "content"]
50
+ }
51
+ }
52
+ }));
53
+ tools
54
+ }
55
+
56
+ pub fn tools_to_anthropic_format(tools: &[serde_json::Value]) -> Vec<serde_json::Value> {
57
+ tools
58
+ .iter()
59
+ .filter_map(|t| {
60
+ let func = t.get("function")?;
61
+ Some(json!({
62
+ "name": func["name"],
63
+ "description": func["description"],
64
+ "input_schema": func["parameters"]
65
+ }))
66
+ })
67
+ .collect()
68
+ }
69
+
70
+ pub fn tools_to_openai_format(tools: &[serde_json::Value]) -> Vec<serde_json::Value> {
71
+ tools.to_vec()
72
+ }