rentman-cli 2.0.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,118 @@
1
+ /**
2
+ * Secure Configuration Module
3
+ * Uses Conf for persistent storage in user's home directory
4
+ * Priority: ENV > Conf > Default
5
+ */
6
+
7
+ const Conf = require('conf');
8
+ const path = require('path');
9
+ const os = require('os');
10
+
11
+ // Initialize Conf with secure defaults
12
+ const config = new Conf({
13
+ projectName: 'rentman',
14
+ cwd: path.join(os.homedir(), '.config'),
15
+ encryptionKey: process.env.RENTMAN_CONFIG_KEY, // Optional encryption
16
+ });
17
+
18
+ /**
19
+ * Get agent identity from secure storage
20
+ * Priority: Environment Variables > Conf Storage
21
+ */
22
+ function getIdentity() {
23
+ // Check environment variables first (most secure for CI/CD)
24
+ if (process.env.RENTMAN_AGENT_ID && process.env.RENTMAN_SECRET_KEY) {
25
+ return {
26
+ agent_id: process.env.RENTMAN_AGENT_ID,
27
+ public_agent_id: process.env.RENTMAN_PUBLIC_AGENT_ID,
28
+ secret_key: process.env.RENTMAN_SECRET_KEY,
29
+ public_key: process.env.RENTMAN_PUBLIC_KEY,
30
+ source: 'environment'
31
+ };
32
+ }
33
+
34
+ // Fallback to Conf storage
35
+ const agent_id = config.get('agent_id');
36
+ const secret_key = config.get('secret_key');
37
+
38
+ if (!agent_id || !secret_key) {
39
+ return null;
40
+ }
41
+
42
+ return {
43
+ agent_id,
44
+ public_agent_id: config.get('public_agent_id'),
45
+ secret_key,
46
+ public_key: config.get('public_key'),
47
+ source: 'config'
48
+ };
49
+ }
50
+
51
+ /**
52
+ * Save agent identity to secure storage
53
+ */
54
+ function saveIdentity(identity) {
55
+ config.set('agent_id', identity.agent_id);
56
+ config.set('public_agent_id', identity.public_agent_id);
57
+ config.set('secret_key', identity.secret_key);
58
+ config.set('public_key', identity.public_key);
59
+
60
+ if (identity.owner_id) {
61
+ config.set('owner_id', identity.owner_id);
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Clear identity (logout)
67
+ */
68
+ function clearIdentity() {
69
+ config.delete('agent_id');
70
+ config.delete('public_agent_id');
71
+ config.delete('secret_key');
72
+ config.delete('public_key');
73
+ config.delete('owner_id');
74
+ }
75
+
76
+ /**
77
+ * Get configuration path
78
+ */
79
+ function getConfigPath() {
80
+ return config.path;
81
+ }
82
+
83
+ /**
84
+ * Get API configuration
85
+ */
86
+ function getApiConfig() {
87
+ return {
88
+ gatewayUrl: process.env.AGENT_GATEWAY_URL || 'https://agent-gateway.rentman.app/v1',
89
+ supabaseUrl: process.env.SUPABASE_URL || 'https://uoekolfgbbmvhzsfkjef.supabase.co',
90
+ supabaseKey: process.env.SUPABASE_ANON_KEY,
91
+ logLevel: process.env.LOG_LEVEL || 'info',
92
+ };
93
+ }
94
+
95
+ /**
96
+ * Get API key (if using API key auth instead of NACL)
97
+ */
98
+ function getApiKey() {
99
+ return process.env.RENTMAN_API_KEY || config.get('api_key');
100
+ }
101
+
102
+ /**
103
+ * Save API key
104
+ */
105
+ function saveApiKey(apiKey) {
106
+ config.set('api_key', apiKey);
107
+ }
108
+
109
+ module.exports = {
110
+ getIdentity,
111
+ saveIdentity,
112
+ clearIdentity,
113
+ getConfigPath,
114
+ getApiConfig,
115
+ getApiKey,
116
+ saveApiKey,
117
+ config, // Expose for custom settings
118
+ };
@@ -0,0 +1,135 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * INTEGRATION TEST: CLI → Supabase
4
+ * Tests task creation without backend/webhook processing
5
+ */
6
+
7
+ const { createClient } = require('@supabase/supabase-js');
8
+ const nacl = require('tweetnacl');
9
+ const naclUtil = require('tweetnacl-util');
10
+
11
+ const SUPABASE_URL = 'https://uoekolfgbbmvhzsfkjef.supabase.co';
12
+ const SUPABASE_ANON_KEY = process.env.SUPABASE_ANON_KEY || 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InVvZWtvbGZnYmJtdmh6c2ZramVmIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzAzMjQzNzUsImV4cCI6MjA4NTkwMDM3NX0.DYxAxi4TTBLgdVruu8uGM3Jog7JZaplWqikAvI0EXvk';
13
+
14
+ async function runIntegrationTest() {
15
+ console.log('\n🔗 INTEGRATION TEST: CLI → Supabase\n');
16
+ console.log('='.repeat(60));
17
+
18
+ const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
19
+ let testsPassed = 0;
20
+ let testsFailed = 0;
21
+
22
+ // Generate test agent
23
+ const keypair = nacl.sign.keyPair();
24
+ const testAgentId = `test-agent-${Date.now()}`;
25
+ const publicKey = naclUtil.encodeBase64(keypair.publicKey);
26
+ const secretKey = keypair.secretKey;
27
+
28
+ console.log(`\n[1] Registering test agent: ${testAgentId}`);
29
+
30
+ try {
31
+ const { data: agent, error } = await supabase
32
+ .from('agents')
33
+ .insert({
34
+ id: testAgentId,
35
+ public_key: publicKey,
36
+ email: `test-${Date.now()}@rentman.test`
37
+ })
38
+ .select()
39
+ .single();
40
+
41
+ if (error) throw error;
42
+ console.log(' ✅ Agent registered');
43
+ testsPassed++;
44
+ } catch (err) {
45
+ console.log(' ❌ Failed:', err.message);
46
+ testsFailed++;
47
+ process.exit(1);
48
+ }
49
+
50
+ // Create signed task
51
+ console.log('\n[2] Creating signed task');
52
+
53
+ const taskData = {
54
+ title: `Integration Test ${new Date().toISOString()}`,
55
+ description: 'Automated integration test',
56
+ task_type: 'verification',
57
+ budget_amount: 10,
58
+ agent_id: testAgentId,
59
+ timestamp: Date.now(),
60
+ nonce: Math.random().toString(36).substring(7)
61
+ };
62
+
63
+ // Sign
64
+ const message = `${taskData.title}:${taskData.agent_id}:${taskData.timestamp}:${taskData.nonce}`;
65
+ const signature = nacl.sign.detached(naclUtil.decodeUTF8(message), secretKey);
66
+ const signatureBase64 = naclUtil.encodeBase64(signature);
67
+
68
+ try {
69
+ const { data: task, error } = await supabase
70
+ .from('tasks')
71
+ .insert({
72
+ title: taskData.title,
73
+ description: taskData.description,
74
+ task_type: taskData.task_type,
75
+ budget_amount: taskData.budget_amount,
76
+ agent_id: taskData.agent_id,
77
+ signature: signatureBase64,
78
+ metadata: taskData,
79
+ status: 'open'
80
+ })
81
+ .select()
82
+ .single();
83
+
84
+ if (error) throw error;
85
+ console.log(' ✅ Task created:', task.id);
86
+ testsPassed++;
87
+
88
+ // Verify task is readable
89
+ console.log('\n[3] Verifying task is readable');
90
+
91
+ const { data: readTask, error: readError } = await supabase
92
+ .from('tasks')
93
+ .select('*')
94
+ .eq('id', task.id)
95
+ .single();
96
+
97
+ if (readError) throw readError;
98
+
99
+ if (readTask.signature !== signatureBase64) {
100
+ throw new Error('Signature mismatch after read');
101
+ }
102
+
103
+ console.log(' ✅ Task readable and signature intact');
104
+ testsPassed++;
105
+
106
+ // Cleanup
107
+ console.log('\n[4] Cleanup test data');
108
+
109
+ await supabase.from('tasks').delete().eq('id', task.id);
110
+ await supabase.from('agents').delete().eq('id', testAgentId);
111
+
112
+ console.log(' ✅ Cleanup complete');
113
+ testsPassed++;
114
+
115
+ } catch (err) {
116
+ console.log(' ❌ Failed:', err.message);
117
+ testsFailed++;
118
+
119
+ // Cleanup on failure
120
+ try {
121
+ await supabase.from('agents').delete().eq('id', testAgentId);
122
+ } catch {}
123
+ }
124
+
125
+ console.log('\n' + '='.repeat(60));
126
+ console.log(`📊 RESULTS: ${testsPassed} passed, ${testsFailed} failed`);
127
+ console.log('='.repeat(60) + '\n');
128
+
129
+ process.exit(testsFailed > 0 ? 1 : 0);
130
+ }
131
+
132
+ runIntegrationTest().catch(err => {
133
+ console.error('💥 Unhandled error:', err);
134
+ process.exit(1);
135
+ });
@@ -0,0 +1,11 @@
1
+ {
2
+ "title": "Verificar funcionamiento V6 (Verbose Logging)",
3
+ "description": "Prueba de depuracion con logs detallados.",
4
+ "task_type": "verification",
5
+ "budget_amount": 75,
6
+ "location": {
7
+ "address": "Cloud Run Server V6",
8
+ "lat": 40.7128,
9
+ "lng": -74.0060
10
+ }
11
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "title": "Verificar funcionamiento V7 (Stderr Logging)",
3
+ "description": "Prueba de depuracion con logs de stderr.",
4
+ "task_type": "verification",
5
+ "budget_amount": 80,
6
+ "location": {
7
+ "address": "Cloud Run Server V7",
8
+ "lat": 40.7128,
9
+ "lng": -74.0060
10
+ }
11
+ }
package/test_task.json ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "title": "Test Delivery Mission",
3
+ "description": "Pick up a package from Office A and deliver it to Building B. Take photo of delivery confirmation.",
4
+ "task_type": "delivery",
5
+ "budget_amount": 25,
6
+ "location_address": "123 Main Street, Downtown",
7
+ "required_skills": [
8
+ "driving",
9
+ "photography"
10
+ ]
11
+ }