Skip to content

Commit

Permalink
Change the standard library pattern for object capabilities
Browse files Browse the repository at this point in the history
  • Loading branch information
SeanTAllen committed Feb 22, 2022
1 parent c8b4d04 commit d172d81
Show file tree
Hide file tree
Showing 26 changed files with 357 additions and 190 deletions.
130 changes: 130 additions & 0 deletions .release-notes/rfc-72.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
## Change standard library object capabilities pattern

We've changed standard library object capabilities pattern.

Object capabilities play an important role in Pony's security story. Developers can via a combination of disallowing the use of FFI within a given package and object capabilities be assured that 3rd-party libraries they use aren't doing unexpected things like opening network sockets.

Joe Eli McIlvain and Sean T. Allen spent some time reviewing the previous usage of object capabilities and came away concerned. We believed the old standard library pattern was:

- Error prone for beginning Pony programmers
- Encouraged passing around AmbientAuth everywhere in a way that negated the advantages of using object capabilities and only left the disadvantages

To learn more about the reasoning for the change, see the [RFC](https://github.com/ponylang/rfcs/blob/main/text/0072-change-stdlib-object-capabilities-pattern.md) that this change implements.

Note, this is a breaking changes and might require you to change your code that involves object capability authorization usage. Only a single "most specific" authorization is now allowed at call sites so previously where you could have been using `AmbientAuth` directly to authorization an action like creating a `TCPListener`:

```pony
TCPListener(env.root, Listener(env.out))
```

You'll now have to use the most specific authorization for the object:

```pony
TCPListener(TCPListenAuth(env.root), Listener(env.out))
```

### Updating authorization for `Backpressure`

Previously accepted:

- `AmbientAuth`
- `ApplyReleaseBackpressureAuth`
- the `BackpressureAuth` type union.

Now accepted:

- `ApplyReleaseBackpressureAuth`

### Updating authorization for `DNS`

Previously accepted:

- `AmbientAuth`
- `NetAuth`
- `DNSAuth`
- the `DNSLookupAuth` type union

Now accepted:

- `DNSAuth`

### Updating authorization for `FilePath`

Previously accepted:

- `AmbientAuth`
- `FileAuth`
- an existing `FilePath` instance

Now accepted:

- `FileAuth`
- an existing `FilePath` instance

### Updating authorization for `ProcessMonitor`

Previously accepted:

- `AmbientAuth`
- `StartProcessAuth`
- the `ProcessMonitorAuth` type union
Now accepted:

- `StartProcessAuth`

### Updating authorization for `RuntimeInfo`

Previously accepted:

- `AmbientAuth`
- `SchedulerInfoAuth`
- the `RuntimeInfoAuth` type union

Now accepted:

- `SchedulerInfoAuth`

### Updating authorization for `Serialised`

No changes are needed.

### Updating authorization for `TCPConnection`

Previously accepted:

- `AmbientAuth`
- `NetAuth`
- `TCPAuth`
- `TCPConnectAuth`
- the `TCPConnectionAuth` type union

Now accepted:

- `TCPConnectAuth`

### Updating authorization for `TCPListener`

Previously accepted:

- `AmbientAuth`
- `NetAuth`
- `TCPAuth`
- `TCPListenAuth`
- the `TCPListenerAuth` type union

Now accepted:

- `TCPListenAuth`

### Updating authorization for `UDPSocket`

Previously accepted:

- `AmbientAuth`
- `NetAuth`
- `UDPAuth`
- the `UDPSocketAuth` type union

Now accepted:

- `UDPAuth`
2 changes: 1 addition & 1 deletion examples/echo/echo.pony
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use "net"

actor Main
new create(env: Env) =>
TCPListener(env.root, Listener(env.out))
TCPListener(TCPListenAuth(env.root), Listener(env.out))

class Listener is TCPListenNotify
let _out: OutStream
Expand Down
2 changes: 1 addition & 1 deletion examples/files/files.pony
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ actor Main

try
with file = OpenFile(
FilePath(env.root, env.args(1)?, caps)) as File
FilePath(CileAuth(env.root), env.args(1)?, caps)) as File
do
env.out.print(file.path.path)
for line in file.lines() do
Expand Down
2 changes: 1 addition & 1 deletion examples/mandelbrot/mandelbrot.pony
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ class val Config
limit = cmd.option("limit").f64().f32()
chunks = cmd.option("chunks").i64().usize()
width = cmd.option("width").i64().usize()
outpath = FilePath(env.root, cmd.option("output").string())
outpath = FilePath(FileAuth(env.root), cmd.option("output").string())

new val none() =>
iterations = 0
Expand Down
2 changes: 1 addition & 1 deletion examples/net/listener.pony
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class Listener is TCPListenNotify

_env.out.print("Client starting")
TCPConnection(
_env.root,
TCPConnectAuth(_env.root),
ClientSide(_env),
_host,
_service)
4 changes: 2 additions & 2 deletions examples/net/net.pony
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ actor Main
1
end

TCPListener(env.root, recover Listener(env, limit) end)
UDPSocket(env.root, recover Pong(env) end)
TCPListener(TCPListenAuth(env.root), recover Listener(env, limit) end)
UDPSocket(UDPAuth(env.root), recover Pong(env) end)
4 changes: 2 additions & 2 deletions examples/net/pong.pony
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ class Pong is UDPNotify
let env = _env

if ip.ip4() then
UDPSocket.ip4(env.root, recover Ping(env, ip) end)
UDPSocket.ip4(UDPAuth(env.root), recover Ping(env, ip) end)
elseif ip.ip6() then
UDPSocket.ip6(env.root, recover Ping(env, ip) end)
UDPSocket.ip6(UDPAuth(env.root), recover Ping(env, ip) end)
else
error
end
Expand Down
7 changes: 4 additions & 3 deletions examples/under_pressure/main.pony
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@ use "time"
use @printf[I32](fmt: Pointer[U8] tag, ...)

class SlowDown is TCPConnectionNotify
let _auth: BackpressureAuth
let _auth: ApplyReleaseBackpressureAuth
let _out: OutStream

new iso create(auth: BackpressureAuth, out: OutStream) =>
new iso create(auth: ApplyReleaseBackpressureAuth, out: OutStream) =>
_auth = auth
_out = out

Expand Down Expand Up @@ -118,7 +118,8 @@ class Send is TimerNotify

actor Main
new create(env: Env) =>
let socket = TCPConnection(env.root, recover SlowDown(env.root, env.out) end,
let socket = TCPConnection(TCPConnectAuth(env.root),
recover SlowDown(ApplyReleaseBackpressureAuth(env.root), env.out) end,
"", "7669")

let timers = Timers
Expand Down
15 changes: 7 additions & 8 deletions packages/backpressure/backpressure.pony
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ it is under pressure.
```pony
// Here we have a TCPConnectionNotify that upon construction
// is given a BackpressureAuth token. This allows the notifier
// is given a ApplyReleaseBackpressureAuth token. This allows the notifier
// to inform the Pony runtime when to apply and release backpressure
// as the connection experiences it.
// Note the calls to
Expand All @@ -49,10 +49,10 @@ use "collections"
use "net"
class SlowDown is TCPConnectionNotify
let _auth: BackpressureAuth
let _auth: ApplyReleaseBackpressureAuth
let _out: StdStream
new iso create(auth: BackpressureAuth, out: StdStream) =>
new iso create(auth: ApplyReleaseBackpressureAuth, out: StdStream) =>
_auth = auth
_out = out
Expand All @@ -70,7 +70,8 @@ class SlowDown is TCPConnectionNotify
actor Main
new create(env: Env) =>
let socket = TCPConnection(env.root,
recover SlowDown(env.root, env.out) end, "", "7669")
recover SlowDown(
ApplyReleaseBackpressureAuth(env.root), env.out) end, "", "7669")
```
## Caveat
Expand All @@ -87,11 +88,9 @@ interfere with the runtime.
use @pony_apply_backpressure[None]()
use @pony_release_backpressure[None]()

type BackpressureAuth is (AmbientAuth | ApplyReleaseBackpressureAuth)

primitive Backpressure
fun apply(auth: BackpressureAuth) =>
fun apply(auth: ApplyReleaseBackpressureAuth) =>
@pony_apply_backpressure()

fun release(auth: BackpressureAuth) =>
fun release(auth: ApplyReleaseBackpressureAuth) =>
@pony_release_backpressure()
Loading

0 comments on commit d172d81

Please sign in to comment.