@@ -1199,6 +1199,126 @@ func (e *Executor) execRevokeODataServiceAccess(s *ast.RevokeODataServiceAccessS
11991199 return fmt .Errorf ("published OData service not found: %s.%s" , s .Service .Module , s .Service .Name )
12001200}
12011201
1202+ // ============================================================================
1203+ // GRANT/REVOKE ACCESS ON PUBLISHED REST SERVICE
1204+ // ============================================================================
1205+
1206+ // execGrantPublishedRestServiceAccess handles GRANT ACCESS ON PUBLISHED REST SERVICE Module.Svc TO roles.
1207+ func (e * Executor ) execGrantPublishedRestServiceAccess (s * ast.GrantPublishedRestServiceAccessStmt ) error {
1208+ if e .writer == nil {
1209+ return fmt .Errorf ("not connected to a project in write mode" )
1210+ }
1211+
1212+ h , err := e .getHierarchy ()
1213+ if err != nil {
1214+ return fmt .Errorf ("failed to build hierarchy: %w" , err )
1215+ }
1216+
1217+ services , err := e .reader .ListPublishedRestServices ()
1218+ if err != nil {
1219+ return fmt .Errorf ("failed to list published REST services: %w" , err )
1220+ }
1221+
1222+ for _ , svc := range services {
1223+ modID := h .FindModuleID (svc .ContainerID )
1224+ modName := h .GetModuleName (modID )
1225+ if modName != s .Service .Module || svc .Name != s .Service .Name {
1226+ continue
1227+ }
1228+
1229+ // Validate all roles exist
1230+ for _ , role := range s .Roles {
1231+ if err := e .validateModuleRole (role ); err != nil {
1232+ return err
1233+ }
1234+ }
1235+
1236+ // Merge new roles with existing (skip duplicates)
1237+ existing := make (map [string ]bool )
1238+ var merged []string
1239+ for _ , r := range svc .AllowedRoles {
1240+ existing [r ] = true
1241+ merged = append (merged , r )
1242+ }
1243+ var added []string
1244+ for _ , role := range s .Roles {
1245+ qn := role .Module + "." + role .Name
1246+ if ! existing [qn ] {
1247+ merged = append (merged , qn )
1248+ added = append (added , qn )
1249+ }
1250+ }
1251+
1252+ if err := e .writer .UpdatePublishedRestServiceRoles (svc .ID , merged ); err != nil {
1253+ return fmt .Errorf ("failed to update published REST service access: %w" , err )
1254+ }
1255+
1256+ if len (added ) == 0 {
1257+ fmt .Fprintf (e .output , "All specified roles already have access on published REST service %s.%s\n " , modName , svc .Name )
1258+ } else {
1259+ fmt .Fprintf (e .output , "Granted access on published REST service %s.%s to %s\n " , modName , svc .Name , strings .Join (added , ", " ))
1260+ }
1261+ return nil
1262+ }
1263+
1264+ return fmt .Errorf ("published REST service not found: %s.%s" , s .Service .Module , s .Service .Name )
1265+ }
1266+
1267+ // execRevokePublishedRestServiceAccess handles REVOKE ACCESS ON PUBLISHED REST SERVICE Module.Svc FROM roles.
1268+ func (e * Executor ) execRevokePublishedRestServiceAccess (s * ast.RevokePublishedRestServiceAccessStmt ) error {
1269+ if e .writer == nil {
1270+ return fmt .Errorf ("not connected to a project in write mode" )
1271+ }
1272+
1273+ h , err := e .getHierarchy ()
1274+ if err != nil {
1275+ return fmt .Errorf ("failed to build hierarchy: %w" , err )
1276+ }
1277+
1278+ services , err := e .reader .ListPublishedRestServices ()
1279+ if err != nil {
1280+ return fmt .Errorf ("failed to list published REST services: %w" , err )
1281+ }
1282+
1283+ for _ , svc := range services {
1284+ modID := h .FindModuleID (svc .ContainerID )
1285+ modName := h .GetModuleName (modID )
1286+ if modName != s .Service .Module || svc .Name != s .Service .Name {
1287+ continue
1288+ }
1289+
1290+ // Build set of roles to remove
1291+ toRemove := make (map [string ]bool )
1292+ for _ , role := range s .Roles {
1293+ toRemove [role .Module + "." + role .Name ] = true
1294+ }
1295+
1296+ // Filter out removed roles
1297+ var remaining []string
1298+ var removed []string
1299+ for _ , r := range svc .AllowedRoles {
1300+ if toRemove [r ] {
1301+ removed = append (removed , r )
1302+ } else {
1303+ remaining = append (remaining , r )
1304+ }
1305+ }
1306+
1307+ if err := e .writer .UpdatePublishedRestServiceRoles (svc .ID , remaining ); err != nil {
1308+ return fmt .Errorf ("failed to update published REST service access: %w" , err )
1309+ }
1310+
1311+ if len (removed ) == 0 {
1312+ fmt .Fprintf (e .output , "None of the specified roles had access on published REST service %s.%s\n " , modName , svc .Name )
1313+ } else {
1314+ fmt .Fprintf (e .output , "Revoked access on published REST service %s.%s from %s\n " , modName , svc .Name , strings .Join (removed , ", " ))
1315+ }
1316+ return nil
1317+ }
1318+
1319+ return fmt .Errorf ("published REST service not found: %s.%s" , s .Service .Module , s .Service .Name )
1320+ }
1321+
12021322// execUpdateSecurity handles UPDATE SECURITY [IN Module].
12031323func (e * Executor ) execUpdateSecurity (s * ast.UpdateSecurityStmt ) error {
12041324 if e .writer == nil {
0 commit comments