We can build this on two reusable functions, like this:
const crossproduct = (xss) =>
  xss.reduce ((ps, xs) => ps.reduce ((r, p) => [...r, ...(xs.map (x => [...p, x]))], []), [[]])
const mergeAll = xs => 
  Object.assign ({}, ...xs)
const combine = (properties, values) => 
  crossproduct (properties.map (p => values.map (v => ({[p]: v}))))
    .map (mergeAll)
const properties = ['arm', 'lens', 'season', 'food', 'size']
const values = [true, false]
console.log (combine (properties, values))
.as-console-wrapper {min-height: 100% !important; top: 0}
 
 
Our utility functions are:
crossproduct, which takes an array of arrays and finds the cartesian product of them.  For instance, 
crossproduct ([['a', 'b', 'c'], [1, 2], ['x', 'y']])
  //=> [["a", 1, "x"], ["a", 1, "y"], ["a", 2, "x"], ["a", 2, "y"], 
  //    ["b", 1, "x"], ["b", 1, "y"], ["b", 2, "x"], ["b", 2, "y"], 
  //    ["c", 1, "x"], ["c", 1, "y"], ["c", 2, "x"], ["c", 2, "y"]]
 
and mergeAll, which combines an array of separate objects into one like this:
mergeAll ([{foo: 1}, {bar: 2}, {baz: 3}])
  //=> {foo: 1, bar: 2, baz: 3}
This is just a thin wrapper around Object.assign, simply applying it to an array rather than individual objects.
 
Our main function, combine first creates an array of arrays matching individual property names to values like this:
  [
    [{"arm": true}, {"arm": false}], 
    [{"lens": true}, {"lens": false}], 
    [{"season": true}, {"season": false}], 
    [{"food": true}, {"food": false}], 
    [{"size": true}, {"size": false}]
]
This is the bit properties.map (p => values.map (v => ({[p]: v}))).  While that could be extracted as a stand-alone function, it doesn't seem to have any other uses, so the decision is simply a matter of code aesthetics.
We call crossproduct on that result, getting this intermediate format:
[
  [{"arm": true}, {"lens": true}, {"season": true}, {"food": true}, {"size": true}], 
  [{"arm": true}, {"lens": true}, {"season": true}, {"food": true}, {"size": false}], 
  [{"arm": true}, {"lens": true}, {"season": true}, {"food": false}, {"size": true}], 
  [{"arm": true}, {"lens": true}, {"season": true}, {"food": false}, {"size": false}],
  // ... 
  [{"arm": false}, {"lens": false}, {"season": false}, {"food": false}, {"size": false}]
]
And finally, we call .map (mergeAll) on that array to get our final format.
Note that if you really have no other use for mergeAll, it's short and can easily be inlined in the main function as .map (xs => Object.assign ({}, ...xs)).  It's a function that I use often and would simply have in handy in my utility toolbox, so I personally wouldn't inline it.  You may feel differently.
Do notice the basic idea here.  We don't try to solve the problem in one go, but rather apply a series of transforms to get to our final format.  This allows us to take advantage of reusable functions for some of those steps.  It's a powerful technique.