Skip to content

Allow for Silent Install of Wifi Profile - #837

Open
outcast36 wants to merge 2 commits into
danielpaulus:mainfrom
greearb:supervised-wifi-profiles
Open

Allow for Silent Install of Wifi Profile#837
outcast36 wants to merge 2 commits into
danielpaulus:mainfrom
greearb:supervised-wifi-profiles

Conversation

@outcast36

@outcast36 outcast36 commented Aug 13, 2026

Copy link
Copy Markdown

The ios wifi command would previously only install the generated profile as if the device were unsupervised. Additionally, even if this was used with a supervised device, the check for supervision would always fail.

Updates wifi command to take a --p12file and a --p12password similar to the ios profile add command. This allows for supervised devices to silently accept the profile.

Proposed wifi command structure:
ios wifi --ssid=my_ssid --password=my_password --enc-type=my_encryption_type --p12file=certificate.p12 --p12password=a

Tested with an iPhone 16 running iOS 26.2.1 on Fedora 39. Supervision was setup using ios prepare

Wyatt Ayers added 2 commits August 12, 2026 18:36
The result of GetCloudConfiguration is a nested map with single
key CloudConfiguration. The IsSupervised key is contained inside
this nested map. This was causing supervised devices to report
being unsupervised.
The wifi command did not allow specifying a p12 certificate with a
password, meaning that the supervised silent install path would not
work. Add p12file and p12password options to wifi command. Should the
device in question be supervised and a p12file + password is given,
add the wifi profile with AddProfileSupervised to silently install.
@danielpaulus

Copy link
Copy Markdown
Owner

/test-devices

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Running real-device tests on PR #837run.

@github-actions

Copy link
Copy Markdown
Contributor

❌ Real-device tests failed — see run.

@outcast36

Copy link
Copy Markdown
Author

From what I can tell, the failing tests are unrelated to changes in these commits. Those being:

    --- PASS: TestAccessibilityAudit/00008120-001905DE2E9B401E (2.25s)
    --- FAIL: TestAccessibilityAudit/00008110-001C58C00A88401E (60.96s)

and

--- FAIL: TestWebInspectorBrowserControl (0.00s)
    --- SKIP: TestWebInspectorBrowserControl/00008120-001905DE2E9B401E (0.15s)
    --- FAIL: TestWebInspectorBrowserControl/00008110-001C58C00A88401E (14.99s)

@danielpaulus

Copy link
Copy Markdown
Owner

You're right, @outcast36 — those two are unrelated to your change. Both TestAccessibilityAudit and TestWebInspectorBrowserControl are failing only on device 00008110-001C58C00A88401E, which is our iOS 26 device — they've been red on that specific device across several unrelated PRs today. It's a known WebInspector/CDP + accessibility-audit problem on iOS 26 that we still owe a fix or a per-device skip; it isn't anything in this PR. The tunnel-free suite and the supervised-wifi paths all passed, so device CI isn't a real blocker here.

Thanks for digging into it 🙏 — I'll follow up with a couple of tiny review notes on the code itself shortly.

@danielpaulus

Copy link
Copy Markdown
Owner

Thanks again @outcast36 — the security side of this is solid (reuses the vetted AddProfileSupervised, no secrets logged). Two things to tighten up and then this is good to merge.

1. isSupervised() — let's make it shape-agnostic so we can merge without a supervised device

Your move to the nested cfg["CloudConfiguration"]["IsSupervised"] is a reasonable inference from how prepare.go writes the config — but we can't actually confirm the GetCloudConfiguration response shape right now: the existing prepare.go/erase.go code fetches that config but never reads a field out of it, there are no fixtures, and we don't have a supervised device on the CI runners to check against. (Filed #839 to add one so supervised-only paths like this get real e2e coverage going forward.)

Rather than commit to one shape, could you make the read work either way? That's strictly safer than both the old (top-level only) and new (nested only) versions, and lets us merge this without waiting on hardware:

func isSupervised(conn *Connection) bool {
    cfg, err := conn.GetCloudConfiguration()
    if err != nil {
        return false
    }
    if cc, ok := cfg["CloudConfiguration"].(map[string]interface{}); ok {
        if s, ok := cc["IsSupervised"].(bool); ok {
            return s
        }
    }
    if s, ok := cfg["IsSupervised"].(bool); ok { // fallback: top-level
        return s
    }
    return false
}

2. A few logging bugs (our golog convention)

The new log lines don't match the house rule, and a couple render !BADKEY because a value is passed without a key. golog is slog-style — every arg after the message must be a "key", value pair, and every line should carry "module", logModule first plus "udid", ... when a device is in scope.

  • golog.Info("PrepareWifi: device supervised: ", supervised)supervised is a lone bool → renders ... !BADKEY=true, and it's missing module/udid. →
    golog.Info("device supervised", "module", logModule, "udid", device.Properties.SerialNumber, "supervised", supervised)
  • golog.Warn("device is supervised, but supervision credentials were not given.", "The Wi-Fi profile must be approved manually...") — the second string is a lone value → !BADKEY. Fold the guidance into the message (or a keyed attr) and add module/udid.
  • golog.Info("Successfully installed wifi profile") — add "module", logModule and "udid", ... (an "ssid", ... attr would be a nice touch too).

Everything else looks good. The only red CI check is the unrelated iOS 26 device flake we discussed, so once these two are in, this is merge-ready. 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants