Skip to content

Commit e93672b

Browse files
TrevorEdwardstswast
authored andcommitted
Fix promises and surface IAP errors in Composer GCF Dag triggering (#776)
1 parent 2c5f854 commit e93672b

File tree

2 files changed

+53
-41
lines changed

2 files changed

+53
-41
lines changed

functions/composer-storage-trigger/index.js

+17-26
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ const FormData = require('form-data');
2929
* https://cloud.google.com/iap/docs/authentication-howto
3030
*
3131
* @param {!Object} event The Cloud Functions event.
32-
* @param {!Function} callback The callback function.
32+
* @returns {Promise}
3333
*/
34-
exports.triggerDag = function triggerDag (event, callback) {
34+
exports.triggerDag = function triggerDag (event) {
3535
// Fill in your Composer environment information here.
3636

3737
// The project that holds your function
@@ -50,12 +50,10 @@ exports.triggerDag = function triggerDag (event, callback) {
5050
const BODY = {'conf': JSON.stringify(event.data)};
5151

5252
// Make the request
53-
authorizeIap(CLIENT_ID, PROJECT_ID, USER_AGENT)
53+
return authorizeIap(CLIENT_ID, PROJECT_ID, USER_AGENT)
5454
.then(function iapAuthorizationCallback (iap) {
55-
makeIapPostRequest(WEBSERVER_URL, BODY, iap.idToken, USER_AGENT, iap.jwt);
56-
})
57-
.then(_ => callback(null))
58-
.catch(callback);
55+
return makeIapPostRequest(WEBSERVER_URL, BODY, iap.idToken, USER_AGENT, iap.jwt);
56+
});
5957
};
6058

6159
/**
@@ -142,24 +140,17 @@ function authorizeIap (clientId, projectId, userAgent) {
142140
* @param {string} jwt A Json web token used to authenticate the request.
143141
*/
144142
function makeIapPostRequest (url, body, idToken, userAgent, jwt) {
145-
var form = new FormData();
146-
form.append('grant_type', 'urn:ietf:params:oauth:grant-type:jwt-bearer');
147-
form.append('assertion', jwt);
148-
149-
return fetch(
150-
url, {
151-
method: 'POST',
152-
body: form
153-
})
154-
.then(function makeIapPostRequestCallback () {
155-
return fetch(url, {
156-
method: 'POST',
157-
headers: {
158-
'User-Agent': userAgent,
159-
'Authorization': `Bearer ${idToken}`
160-
},
161-
body: JSON.stringify(body)
162-
});
163-
});
143+
return fetch(url, {
144+
method: 'POST',
145+
headers: {
146+
'User-Agent': userAgent,
147+
'Authorization': `Bearer ${idToken}`
148+
},
149+
body: JSON.stringify(body)
150+
}).then(function checkIapRequestStatus (res) {
151+
if (!res.ok) {
152+
return res.text().then(body => Promise.reject(body));
153+
}
154+
});
164155
}
165156
// [END composer_trigger]

functions/composer-storage-trigger/test/index.test.js

+36-15
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,13 @@ const proxyquire = require(`proxyquire`).noCallThru();
1919
const sinon = require(`sinon`);
2020
const test = require(`ava`);
2121

22-
function getSample () {
23-
const bodyJson = {};
24-
const body = {
25-
json: sinon.stub().resolves(bodyJson)
26-
};
27-
const FetchMock = sinon.stub().resolves(body);
28-
22+
function getSample (FetchStub) {
2923
return {
3024
program: proxyquire(`../`, {
31-
'node-fetch': FetchMock
25+
'node-fetch': FetchStub
3226
}),
3327
mocks: {
34-
fetch: FetchMock,
35-
body: body,
36-
bodyJson: bodyJson
28+
fetch: FetchStub
3729
}
3830
};
3931
}
@@ -45,12 +37,41 @@ test.cb(`Handles error in JSON body`, (t) => {
4537
}
4638
};
4739
const expectedMsg = `Something bad happened.`;
48-
const sample = getSample();
49-
sample.mocks.bodyJson.error = expectedMsg;
40+
const bodyJson = {'error': expectedMsg};
41+
const body = {
42+
json: sinon.stub().resolves(bodyJson)
43+
};
44+
const sample = getSample(sinon.stub().resolves(body));
5045

51-
sample.program.triggerDag(event, (err, message) => {
46+
sample.program.triggerDag(event).catch(function (err) {
5247
t.regex(err, /Something bad happened/);
53-
t.is(message, undefined);
48+
t.end();
49+
});
50+
});
51+
52+
test.cb(`Handles error in IAP response.`, (t) => {
53+
const event = {
54+
data: {
55+
file: `some-file`
56+
}
57+
};
58+
const expectedMsg = 'Default IAP Error Message.';
59+
60+
const serviceAccountAccessTokenRes = {
61+
json: sinon.stub().resolves({'access_token': 'default-access-token'})
62+
};
63+
const signJsonClaimRes = {json: sinon.stub().resolves({'signature': 'default-jwt-signature'})};
64+
const getTokenRes = {json: sinon.stub().resolves({'id_token': 'default-id-token'})};
65+
const makeIapPostRequestRes = {ok: false, text: sinon.stub().resolves(expectedMsg)};
66+
const FetchStub = sinon.stub()
67+
.onCall(0).resolves(serviceAccountAccessTokenRes)
68+
.onCall(1).resolves(signJsonClaimRes)
69+
.onCall(2).resolves(getTokenRes)
70+
.onCall(3).resolves(makeIapPostRequestRes);
71+
const sample = getSample(FetchStub);
72+
73+
sample.program.triggerDag(event).catch(function (err) {
74+
t.is(err, expectedMsg);
5475
t.end();
5576
});
5677
});

0 commit comments

Comments
 (0)