Skip to content

Commit e1b5980

Browse files
Ace NassriJustinBeckwith
authored andcommitted
chore(functions): address comments on CAL samples (#2402)
* chore(functions): address comments on CAL samples * Fix lint * Remove stray dbg statement * Address comments * nit Co-authored-by: Justin Beckwith <[email protected]>
1 parent ccaef0e commit e1b5980

File tree

3 files changed

+77
-12
lines changed

3 files changed

+77
-12
lines changed

functions/v2/index.js

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ exports.helloGCS = cloudevent => {
5656

5757
// [START functions_log_cloudevent]
5858
/**
59-
* CloudEvent function to be triggered by Cloud Audit Logging
59+
* CloudEvent function to be triggered by an Eventarc Cloud Audit Logging trigger
60+
* Note: this is NOT designed for second-party (Cloud Audit Logs -> Pub/Sub) triggers!
6061
*
6162
* @param {object} cloudevent A CloudEvent containing the Cloud Audit Log entry.
6263
* @param {object} cloudevent.data.protoPayload The Cloud Audit Log entry itself.
@@ -68,8 +69,21 @@ exports.helloAuditLog = cloudevent => {
6869
console.log('Subject:', cloudevent.subject);
6970

7071
// Print out details from the Cloud Audit Logging entry
71-
const payload = cloudevent.data.protoPayload;
72-
console.log('Principal:', payload.authenticationInfo.principalEmail);
72+
const payload = cloudevent.data && cloudevent.data.protoPayload;
73+
if (payload) {
74+
console.log('Resource name:', payload.resourceName);
75+
}
76+
77+
const request = payload.request;
78+
if (request) {
79+
console.log('Request type:', request['@type']);
80+
}
81+
82+
const metadata = payload && payload.requestMetadata;
83+
if (metadata) {
84+
console.log('Caller IP:', metadata.callerIp);
85+
console.log('User agent:', metadata.callerSuppliedUserAgent);
86+
}
7387
};
7488
// [END functions_log_cloudevent]
7589

@@ -86,12 +100,19 @@ const instancesClient = new compute.InstancesClient();
86100
*/
87101
exports.autoLabelInstance = async cloudevent => {
88102
// Extract parameters from the CloudEvent + Cloud Audit Log data
89-
let creator = cloudevent.data.protoPayload.authenticationInfo.principalEmail;
103+
const payload = cloudevent.data && cloudevent.data.protoPayload;
104+
const authInfo = payload && payload.authenticationInfo;
105+
let creator = authInfo && authInfo.principalEmail;
90106

91107
// Get relevant VM instance details from the cloudevent's `subject` property
92108
// Example value:
93109
// compute.googleapis.com/projects/<PROJECT>/zones/<ZONE>/instances/<INSTANCE>
94-
const params = cloudevent.subject.split('/');
110+
const params = cloudevent.subject && cloudevent.subject.split('/');
111+
112+
// Validate data
113+
if (!creator || !params || params.length !== 7) {
114+
throw new Error('Invalid event structure');
115+
}
95116

96117
// Format the 'creator' parameter to match GCE label validation requirements
97118
creator = creator.toLowerCase().replace(/\W/g, '_');

functions/v2/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
"node": ">=12.0.0"
1313
},
1414
"scripts": {
15-
"test": "mocha test/index.test.js",
16-
"e2e-test": "mocha test/*.test.js"
15+
"test": "mocha --timeout 30s test/index.test.js",
16+
"e2e-test": "mocha --timeout 60s test/*.test.js"
1717
},
1818
"dependencies": {
1919
"@google-cloud/compute": "^3.0.0-alpha.4"

functions/v2/test/index.test.js

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const getFFOutput = ffProc => {
3131
let stderr = '';
3232
ffProc.stdout.on('data', data => (stdout += data));
3333
ffProc.stderr.on('data', data => (stderr += data));
34+
3435
ffProc.on('error', reject).on('exit', code => {
3536
code === 0 ? resolve(stdout) : reject(stderr);
3637
});
@@ -113,6 +114,7 @@ describe('functions_cloudevent_storage', () => {
113114
ffProc.kill();
114115

115116
const output = await ffProcHandler;
117+
console.log();
116118

117119
assert.strictEqual(response.status, 204);
118120
assert.match(output, /Event ID: 1234/);
@@ -143,15 +145,20 @@ describe('functions_log_cloudevent', () => {
143145

144146
it('should process a CloudEvent', async () => {
145147
const event = {
146-
methodname: 'storage.objects.create',
148+
methodname: 'storage.objects.write',
147149
type: 'google.cloud.audit.log.v1.written',
148150
subject:
149151
'storage.googleapis.com/projects/_/buckets/my-bucket/objects/test.txt',
150152
data: {
151153
protoPayload: {
152-
authenticationInfo: {
153-
principalEmail: '[email protected]',
154+
requestMetadata: {
155+
callerIp: '8.8.8.8',
156+
callerSuppliedUserAgent: 'example-user-agent',
157+
},
158+
request: {
159+
'@type': 'type.googleapis.com/storage.objects.write',
154160
},
161+
resourceName: 'some-resource',
155162
},
156163
},
157164
};
@@ -161,12 +168,49 @@ describe('functions_log_cloudevent', () => {
161168
const output = await ffProcHandler;
162169

163170
assert.strictEqual(response.status, 204);
164-
assert.match(output, /API method: storage\.objects\.create/);
171+
assert.match(output, /API method: storage\.objects\.write/);
165172
assert.match(output, /Event type: google.cloud.audit.log.v1.written/);
166173
assert.match(
167174
output,
168175
/Subject: storage.googleapis.com\/projects\/_\/buckets\/my-bucket\/objects\/test\.txt/
169176
);
170-
assert.match(output, /Principal: nobody@example\.com/);
177+
assert.match(output, /Resource name: some-resource/);
178+
assert.match(
179+
output,
180+
/Request type: type\.googleapis\.com\/storage\.objects.write/
181+
);
182+
assert.match(output, /Caller IP: 8\.8\.8\.8/);
183+
assert.match(output, /User agent: example-user-agent/);
184+
});
185+
});
186+
187+
describe('functions_label_gce_instance', () => {
188+
const PORT = 9084;
189+
let ffProc;
190+
let ffProcHandler;
191+
192+
before(async () => {
193+
ffProc = await startFF('autoLabelInstance', 'cloudevent', PORT);
194+
ffProcHandler = getFFOutput(ffProc);
195+
});
196+
197+
after(() => {
198+
// Stop any residual Functions Framework instances
199+
try {
200+
ffProc.kill();
201+
} finally {
202+
/* Do nothing */
203+
}
204+
});
205+
206+
it('should validate data', async () => {
207+
const event = {
208+
subject: 'invalid/subject/example',
209+
};
210+
const response = await invocation(PORT, event);
211+
ffProc.kill();
212+
213+
await ffProcHandler;
214+
assert.match(response.data, /Invalid event structure/);
171215
});
172216
});

0 commit comments

Comments
 (0)