2025-06-12 18:23:49 +00:00
module . exports = {
friendlyName : 'Modify android policies' ,
description : 'Modifies a policy of an Android enterprise' ,
inputs : {
androidEnterpriseId : {
type : 'string' ,
required : true ,
} ,
policyId : {
type : 'string' ,
required : true ,
} ,
} ,
exits : {
2025-10-10 22:11:42 +00:00
success : { description : 'The policy of an Android enterprise was successfully updated.' } ,
missingAuthHeader : { description : 'This request was missing an authorization header.' , responseType : 'unauthorized' } ,
unauthorized : { description : 'Invalid authentication token.' , responseType : 'unauthorized' } ,
notFound : { description : 'No Android enterprise found for this Fleet server.' , responseType : 'notFound' } ,
2026-01-28 15:57:27 +00:00
invalidPolicy : { description : 'Invalid patch policy request' , responseType : 'badRequest' } ,
2026-02-19 23:46:41 +00:00
policyNotFound : { description : 'The specified policy was not found on this Android enterprise' , responseType : 'notFound' } ,
2025-06-12 18:23:49 +00:00
} ,
fn : async function ( { androidEnterpriseId , policyId } ) {
// Extract fleetServerSecret from the Authorization header
let authHeader = this . req . get ( 'authorization' ) ;
let fleetServerSecret ;
if ( authHeader && authHeader . startsWith ( 'Bearer' ) ) {
fleetServerSecret = authHeader . replace ( 'Bearer' , '' ) . trim ( ) ;
} else {
2025-10-10 22:11:42 +00:00
throw 'missingAuthHeader' ;
2025-06-12 18:23:49 +00:00
}
// Authenticate this request
let thisAndroidEnterprise = await AndroidEnterprise . findOne ( {
androidEnterpriseId : androidEnterpriseId
} ) ;
// Return a 404 response if no records are found.
if ( ! thisAndroidEnterprise ) {
2025-10-10 22:11:42 +00:00
throw 'notFound' ;
2025-06-12 18:23:49 +00:00
}
// Return an unauthorized response if the provided secret does not match.
if ( thisAndroidEnterprise . fleetServerSecret !== fleetServerSecret ) {
2025-10-10 22:11:42 +00:00
throw 'unauthorized' ;
2025-06-12 18:23:49 +00:00
}
2025-10-06 17:50:42 +00:00
// Check the list of Android Enterprises managed by Fleet to see if this Android Enterprise is still managed.
let isEnterpriseManagedByFleet = await sails . helpers . androidProxy . getIsEnterpriseManagedByFleet ( androidEnterpriseId ) ;
// Return a 404 response if this Android enterprise is no longer managed by Fleet.
if ( ! isEnterpriseManagedByFleet ) {
2025-10-10 22:11:42 +00:00
throw 'notFound' ;
2025-10-06 17:50:42 +00:00
}
2025-06-12 18:23:49 +00:00
// Update the policy for this Android enterprise.
// Note: We're using sails.helpers.flow.build here to handle any errors that occurr using google's node library.
let modifyPoliciesResponse = await sails . helpers . flow . build ( async ( ) => {
let { google } = require ( 'googleapis' ) ;
let androidmanagement = google . androidmanagement ( 'v1' ) ;
let googleAuth = new google . auth . GoogleAuth ( {
scopes : [ 'https://www.googleapis.com/auth/androidmanagement' ] ,
credentials : {
client _email : sails . config . custom . androidEnterpriseServiceAccountEmailAddress , // eslint-disable-line camelcase
private _key : sails . config . custom . androidEnterpriseServiceAccountPrivateKey , // eslint-disable-line camelcase
} ,
} ) ;
// Acquire the google auth client, and bind it to all future calls
let authClient = await googleAuth . getClient ( ) ;
google . options ( { auth : authClient } ) ;
// [?]: https://googleapis.dev/nodejs/googleapis/latest/androidmanagement/classes/Resource$Enterprises$Policies.html#patch
let patchPoliciesResponse = await androidmanagement . enterprises . policies . patch ( {
name : ` enterprises/ ${ androidEnterpriseId } /policies/ ${ policyId } ` ,
2026-03-07 00:06:25 +00:00
// Note: Typically, we use defined inputs instead of accessing req.body directly. We forward req.body here to prevent previously set values from being overwritten by undefined values.
// This behavior should not be repeated in future Android proxy endpoints.
2025-06-12 18:23:49 +00:00
requestBody : this . req . body ,
2025-11-13 23:10:24 +00:00
updateMask : this . req . param ( 'updateMask' ) // Pass the update mask to avoid overwriting applications
2025-06-12 18:23:49 +00:00
} ) ;
return patchPoliciesResponse . data ;
2026-01-28 15:57:27 +00:00
} ) . intercept ( { status : 429 } , ( err ) => {
2025-11-12 21:37:21 +00:00
// If the Android management API returns a 429 response, log an additional warning that will trigger a help-p1 alert.
sails . log . warn ( ` p1: Android management API rate limit exceeded! ` ) ;
return new Error ( ` When attempting to update a policy for an Android enterprise ( ${ androidEnterpriseId } ), an error occurred. Error: ${ err } ` ) ;
2026-01-28 15:57:27 +00:00
} ) . intercept ( { status : 400 } , ( err ) => {
return { 'invalidPolicy' : ` Attempted to update a policy with an invalid value for an Android enterprise ( ${ androidEnterpriseId } ): ${ err } ` } ;
2026-02-19 23:46:41 +00:00
} ) . intercept ( { status : 404 } , ( err ) => {
return { 'policyNotFound' : ` Specified policy not found on this Android enterprise ( ${ androidEnterpriseId } ): ${ err } ` } ;
2026-01-28 15:57:27 +00:00
} ) . intercept ( ( err ) => {
2026-02-19 23:46:41 +00:00
return new Error ( ` When attempting to update a policy for an Android enterprise ( ${ androidEnterpriseId } ), an error occurred. Error: ${ require ( 'util' ) . inspect ( err ) } ` ) ;
2025-06-12 18:23:49 +00:00
} ) ;
// Return the modified policy back to the Fleet server.
return modifyPoliciesResponse ;
}
} ;