[sestarnix][policy] Normalize constraint terms for testing

The order of operands seems to depend on the policy
compiler version, at least for context expressions
with commutative operators.

Bug: 372400976
Change-Id: Ib7724cfd546ad6513da798b95b4b56473a21aaf1
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/1221053
Commit-Queue: Laura Peskin <pesk@google.com>
Fuchsia-Auto-Submit: Laura Peskin <pesk@google.com>
Reviewed-by: Wez <wez@google.com>
diff --git a/src/starnix/lib/selinux/src/policy/constraints.rs b/src/starnix/lib/selinux/src/policy/constraints.rs
index d070b13..059c8ec 100644
--- a/src/starnix/lib/selinux/src/policy/constraints.rs
+++ b/src/starnix/lib/selinux/src/policy/constraints.rs
@@ -369,8 +369,42 @@
     use super::*;
     use crate::policy::{find_class_by_name, parse_policy_by_reference};
 
+    fn normalize_context_expr(expr: ContextExpression) -> ContextExpression {
+        let (left, right) = match expr.operator {
+            ContextOperator::Dominates | ContextOperator::DominatedBy => (expr.left, expr.right),
+            ContextOperator::Equal | ContextOperator::NotEqual | ContextOperator::Incomparable => {
+                match (&expr.left, &expr.right) {
+                    (ContextOperand::UserId(left), ContextOperand::UserId(right)) => (
+                        ContextOperand::UserId(std::cmp::min(*left, *right)),
+                        ContextOperand::UserId(std::cmp::max(*left, *right)),
+                    ),
+                    (ContextOperand::TypeId(left), ContextOperand::TypeId(right)) => (
+                        ContextOperand::TypeId(std::cmp::min(*left, *right)),
+                        ContextOperand::TypeId(std::cmp::max(*left, *right)),
+                    ),
+                    (ContextOperand::RoleId(left), ContextOperand::RoleId(right)) => (
+                        ContextOperand::RoleId(std::cmp::min(*left, *right)),
+                        ContextOperand::RoleId(std::cmp::max(*left, *right)),
+                    ),
+                    _ => (expr.left, expr.right),
+                }
+            }
+        };
+        ContextExpression { operator: expr.operator, left, right }
+    }
+
+    fn normalize(expr: Vec<ConstraintNode>) -> Vec<ConstraintNode> {
+        expr.into_iter()
+            .map(|node| match node {
+                ConstraintNode::Leaf(context_expr) => {
+                    ConstraintNode::Leaf(normalize_context_expr(context_expr))
+                }
+                ConstraintNode::Branch(_) => node,
+            })
+            .collect()
+    }
+
     #[test]
-    #[ignore = "TODO: Fix test to accommodate apparent non-determinism in commutative operator arguments"]
     fn decode_constraint_expr() {
         let policy_bytes = include_bytes!("../../testdata/micro_policies/constraints_policy.pp");
         let policy = parse_policy_by_reference(policy_bytes.as_slice())
@@ -396,7 +430,7 @@
             .iter()
             .map(|x| ConstraintNode::try_from_constraint_term(x, &source, &target))
             .collect();
-        assert!(result.is_ok());
+        let constraint_nodes = normalize(result.expect("decode constraint terms"));
         let expected = vec![
             // ( u2 == { user0 user1 } )
             ConstraintNode::Leaf(ContextExpression {
@@ -435,7 +469,7 @@
             ConstraintNode::Branch(BooleanOperator::Or),
         ];
 
-        assert_eq!(result.unwrap(), expected)
+        assert_eq!(constraint_nodes, expected)
     }
 
     #[test]
diff --git a/src/starnix/lib/selinux/src/policy/mod.rs b/src/starnix/lib/selinux/src/policy/mod.rs
index 0417c1f59..8df7ed3 100644
--- a/src/starnix/lib/selinux/src/policy/mod.rs
+++ b/src/starnix/lib/selinux/src/policy/mod.rs
@@ -38,15 +38,15 @@
 pub const SUPPORTED_POLICY_VERSION: u32 = 33;
 
 /// Identifies a user within a policy.
-#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
 pub struct UserId(NonZeroU32);
 
 /// Identifies a role within a policy.
-#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
 pub struct RoleId(NonZeroU32);
 
 /// Identifies a type within a policy.
-#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
 pub struct TypeId(NonZeroU32);
 
 /// Identifies a sensitivity level within a policy.